diff options
author | xrs <xrs@mail36.net> | 2020-01-16 17:12:09 +0100 |
---|---|---|
committer | xrs <xrs@mail36.net> | 2020-01-16 17:12:09 +0100 |
commit | 32b55237f2b94b4940d7031a0bc1adcf8b63824a (patch) | |
tree | 92766aa532ef2c674192dc3bd0e9b71a99829fa1 /src | |
parent | ec78709681261eaddedbed6484dd95849f180f92 (diff) | |
parent | 5177efb74f9301bbffd79d63f47eb78611e6abba (diff) |
Merge branch 'master' of ssh://git.gnunet.org/gnunet
Diffstat (limited to 'src')
45 files changed, 5008 insertions, 466 deletions
diff --git a/src/Makefile.am b/src/Makefile.am index 1bcc1ae7b..7b73a4bb8 100644 --- a/src/Makefile.am +++ b/src/Makefile.am @@ -66,12 +66,6 @@ endif endif -if TALER_ONLY -SUBDIRS = \ - include \ - util -else - SUBDIRS = \ include $(INTLEMU_SUBDIRS) \ util \ @@ -128,5 +122,3 @@ SUBDIRS = \ $(RECLAIM_DIR) \ $(EXP_DIR) \ integration-tests - -endif diff --git a/src/curl/curl.c b/src/curl/curl.c index dcbb43f58..82eb28ed9 100644 --- a/src/curl/curl.c +++ b/src/curl/curl.c @@ -680,7 +680,7 @@ do_benchmark (CURLMsg *cmsg) /** - * Run the main event loop for the Taler interaction. + * Run the main event loop for the HTTP interaction. * * @param ctx the library context * @param rp parses the raw response returned from diff --git a/src/gns/gns.h b/src/gns/gns.h index 1fa812c23..5f51b7108 100644 --- a/src/gns/gns.h +++ b/src/gns/gns.h @@ -1,6 +1,6 @@ /* This file is part of GNUnet - Copyright (C) 2012-2013 GNUnet e.V. + Copyright (C) 2012-2020 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 @@ -57,9 +57,11 @@ struct LookupMessage int16_t options GNUNET_PACKED; /** - * Always 0. + * Recursion depth limit, i.e. how many more + * GNS zones may be traversed during the resolution + * of this name. */ - int16_t reserved GNUNET_PACKED; + uint16_t recursion_depth_limit GNUNET_PACKED; /** * the type of record to look up diff --git a/src/gns/gns_api.c b/src/gns/gns_api.c index 4a4003b2a..0d99d822e 100644 --- a/src/gns/gns_api.c +++ b/src/gns/gns_api.c @@ -1,6 +1,6 @@ /* This file is part of GNUnet. - Copyright (C) 2009-2013, 2016, 2018 GNUnet e.V. + Copyright (C) 2009-2020 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 @@ -37,6 +37,12 @@ #define LOG(kind, ...) GNUNET_log_from (kind, "gns-api", __VA_ARGS__) /** + * Default recursion depth limit to apply if + * the application does not specify any. + */ +#define DEFAULT_LIMIT 128 + +/** * Handle to a lookup request */ struct GNUNET_GNS_LookupRequest @@ -325,21 +331,24 @@ GNUNET_GNS_lookup_cancel (struct GNUNET_GNS_LookupRequest *lr) * * @param handle handle to the GNS service * @param name the name to look up (in UTF-8 encoding) - * @param zone the zone to start the resolution in - * @param type the record type to look up + * @param zone zone to look in + * @param type the GNS record type to look for * @param options local options for the lookup - * @param proc processor to call on result + * @param recursion_depth_limit maximum number of zones + * that the lookup may (still) traverse + * @param proc function to call on result * @param proc_cls closure for @a proc - * @return handle to the get request + * @return handle to the queued request */ -struct GNUNET_GNS_LookupRequest* -GNUNET_GNS_lookup (struct GNUNET_GNS_Handle *handle, - const char *name, - const struct GNUNET_CRYPTO_EcdsaPublicKey *zone, - uint32_t type, - enum GNUNET_GNS_LocalOptions options, - GNUNET_GNS_LookupResultProcessor proc, - void *proc_cls) +struct GNUNET_GNS_LookupRequest * +GNUNET_GNS_lookup_limited (struct GNUNET_GNS_Handle *handle, + const char *name, + const struct GNUNET_CRYPTO_EcdsaPublicKey *zone, + uint32_t type, + enum GNUNET_GNS_LocalOptions options, + uint16_t recursion_depth_limit, + GNUNET_GNS_LookupResultProcessor proc, + void *proc_cls) { /* IPC to shorten gns names, return shorten_handle */ struct LookupMessage *lookup_msg; @@ -370,6 +379,8 @@ GNUNET_GNS_lookup (struct GNUNET_GNS_Handle *handle, GNUNET_MESSAGE_TYPE_GNS_LOOKUP); lookup_msg->id = htonl (lr->r_id); lookup_msg->options = htons ((uint16_t) options); + lookup_msg->recursion_depth_limit + = htons (recursion_depth_limit); lookup_msg->zone = *zone; lookup_msg->type = htonl (type); GNUNET_memcpy (&lookup_msg[1], @@ -385,4 +396,35 @@ GNUNET_GNS_lookup (struct GNUNET_GNS_Handle *handle, } +/** + * Perform an asynchronous lookup operation on the GNS. + * + * @param handle handle to the GNS service + * @param name the name to look up (in UTF-8 encoding) + * @param zone the zone to start the resolution in + * @param type the record type to look up + * @param options local options for the lookup + * @param proc processor to call on result + * @param proc_cls closure for @a proc + * @return handle to the get request + */ +struct GNUNET_GNS_LookupRequest* +GNUNET_GNS_lookup (struct GNUNET_GNS_Handle *handle, + const char *name, + const struct GNUNET_CRYPTO_EcdsaPublicKey *zone, + uint32_t type, + enum GNUNET_GNS_LocalOptions options, + GNUNET_GNS_LookupResultProcessor proc, + void *proc_cls) +{ + return GNUNET_GNS_lookup_limited (handle, + name, + zone, + type, + options, + DEFAULT_LIMIT, + proc, + proc_cls); +} + /* end of gns_api.c */ diff --git a/src/gns/gnunet-service-gns.c b/src/gns/gnunet-service-gns.c index 99cdbfe4e..8c5b2d6c4 100644 --- a/src/gns/gnunet-service-gns.c +++ b/src/gns/gnunet-service-gns.c @@ -463,6 +463,7 @@ handle_lookup (void *cls, name, (enum GNUNET_GNS_LocalOptions) ntohs ( sh_msg->options), + ntohs (sh_msg->recursion_depth_limit), &send_lookup_response, clh); GNUNET_STATISTICS_update (statistics, "Lookup attempts", diff --git a/src/gns/gnunet-service-gns_interceptor.c b/src/gns/gnunet-service-gns_interceptor.c index dd97782ae..9d6636e84 100644 --- a/src/gns/gnunet-service-gns_interceptor.c +++ b/src/gns/gnunet-service-gns_interceptor.c @@ -34,6 +34,12 @@ /** + * How deep do we allow recursions to go before we abort? + */ +#define MAX_RECURSION 256 + + +/** * Handle to a DNS intercepted * reslution request */ @@ -347,6 +353,7 @@ handle_dns_request (void *cls, p->queries[0].type, p->queries[0].name, GNUNET_NO, + MAX_RECURSION, &reply_to_dns, ilh); return; } diff --git a/src/gns/gnunet-service-gns_resolver.c b/src/gns/gnunet-service-gns_resolver.c index 2c2263e58..735742283 100644 --- a/src/gns/gnunet-service-gns_resolver.c +++ b/src/gns/gnunet-service-gns_resolver.c @@ -77,11 +77,6 @@ */ #define DHT_GNS_REPLICATION_LEVEL 10 -/** - * How deep do we allow recursions to go before we abort? - */ -#define MAX_RECURSION 256 - /** * DLL to hold the authority chain we had to pass in the resolution @@ -320,7 +315,7 @@ struct GNS_ResolverHandle /** * closure passed to @e proc */ - void*proc_cls; + void *proc_cls; /** * Handle for DHT lookups. should be NULL if no lookups are in progress @@ -395,7 +390,7 @@ struct GNS_ResolverHandle struct DnsResult *dns_result_tail; /** - * Current offset in 'name' where we are resolving. + * Current offset in @e name where we are resolving. */ size_t name_resolution_pos; @@ -423,12 +418,17 @@ struct GNS_ResolverHandle /** * We increment the loop limiter for each step in a recursive - * resolution. If it passes our threshold (i.e. due to + * resolution. If it passes our @e loop_threshold (i.e. due to * self-recursion in the resolution, i.e CNAME fun), we stop. */ unsigned int loop_limiter; /** + * Maximum value of @e loop_limiter allowed by client. + */ + unsigned int loop_threshold; + + /** * 16 bit random ID we used in the @e dns_request. */ uint16_t original_dns_id; @@ -1856,6 +1856,7 @@ recursive_gns2dns_resolution (struct GNS_ResolverHandle *rh, gp->rh->record_type = GNUNET_GNSRECORD_TYPE_ANY; gp->rh->options = GNUNET_GNS_LO_DEFAULT; gp->rh->loop_limiter = rh->loop_limiter + 1; + gp->rh->loop_threshold = rh->loop_threshold; gp->rh->task_id = GNUNET_SCHEDULER_add_now (&start_resolver_lookup, gp->rh); @@ -2744,7 +2745,7 @@ recursive_resolution (void *cls) struct GNS_ResolverHandle *rh = cls; rh->task_id = NULL; - if (MAX_RECURSION < rh->loop_limiter++) + if (rh->loop_threshold < rh->loop_limiter++) { GNUNET_log (GNUNET_ERROR_TYPE_WARNING, "Encountered unbounded recursion resolving `%s'\n", @@ -2840,6 +2841,8 @@ start_resolver_lookup (void *cls) * @param record_type the record type to look up * @param name the name to look up * @param options local options to control local lookup + * @param recursion_depth_limit how many zones to traverse + * at most * @param proc the processor to call on result * @param proc_cls the closure to pass to @a proc * @return handle to cancel operation @@ -2849,6 +2852,7 @@ GNS_resolver_lookup (const struct GNUNET_CRYPTO_EcdsaPublicKey *zone, uint32_t record_type, const char *name, enum GNUNET_GNS_LocalOptions options, + uint16_t recursion_depth_limit, GNS_ResultProcessor proc, void *proc_cls) { @@ -2868,6 +2872,7 @@ GNS_resolver_lookup (const struct GNUNET_CRYPTO_EcdsaPublicKey *zone, rh->record_type = record_type; rh->name = GNUNET_strdup (name); rh->name_resolution_pos = strlen (name); + rh->loop_threshold = recursion_depth_limit; rh->task_id = GNUNET_SCHEDULER_add_now (&start_resolver_lookup, rh); return rh; diff --git a/src/gns/gnunet-service-gns_resolver.h b/src/gns/gnunet-service-gns_resolver.h index cc918fd90..3dab3c91a 100644 --- a/src/gns/gnunet-service-gns_resolver.h +++ b/src/gns/gnunet-service-gns_resolver.h @@ -1,6 +1,6 @@ /* This file is part of GNUnet. - Copyright (C) 2009-2013 GNUnet e.V. + Copyright (C) 2009-2020 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 @@ -79,6 +79,8 @@ typedef void * @param record_type the record type to look up * @param name the name to look up * @param options options set to control local lookup + * @param recursion_depth_limit how many zones to traverse + * at most * @param proc the processor to call * @param proc_cls the closure to pass to @a proc * @return handle to cancel operation @@ -88,6 +90,7 @@ GNS_resolver_lookup (const struct GNUNET_CRYPTO_EcdsaPublicKey *zone, uint32_t record_type, const char *name, enum GNUNET_GNS_LocalOptions options, + uint16_t recursion_depth_limit, GNS_ResultProcessor proc, void *proc_cls); diff --git a/src/include/Makefile.am b/src/include/Makefile.am index c81f8e7d8..b53f2420d 100644 --- a/src/include/Makefile.am +++ b/src/include/Makefile.am @@ -9,17 +9,6 @@ EXTRA_DIST = \ block_dns.h \ block_regex.h -if TALER_ONLY -gnunetinclude_HEADERS = \ - platform.h gettext.h \ - gnunet_common.h \ - gnunet_container_lib.h \ - gnunet_crypto_lib.h \ - gnunet_strings_lib.h \ - gnunet_time_lib.h \ - gnunet_util_taler_wallet_lib.h -else - gnunetinclude_HEADERS = \ platform.h gettext.h \ compat.h \ @@ -35,6 +24,7 @@ gnunetinclude_HEADERS = \ gnunet_block_lib.h \ gnunet_block_group_lib.h \ gnunet_block_plugin.h \ + gnunet_buffer_lib.h \ gnunet_client_lib.h \ gnunet_common.h \ gnunet_constants.h \ @@ -101,7 +91,7 @@ gnunetinclude_HEADERS = \ gnunet_regex_service.h \ gnunet_rest_lib.h \ gnunet_rest_plugin.h \ - gnunet_rps_service.h \ + gnunet_rps_service.h \ gnunet_revocation_service.h \ gnunet_scalarproduct_service.h \ gnunet_scheduler_lib.h \ @@ -130,5 +120,3 @@ gnunetinclude_HEADERS = \ gnunet_tun_lib.h \ gnunet_util_lib.h \ gnunet_vpn_service.h - -endif diff --git a/src/include/gnunet_buffer_lib.h b/src/include/gnunet_buffer_lib.h new file mode 100644 index 000000000..c0ae06d77 --- /dev/null +++ b/src/include/gnunet_buffer_lib.h @@ -0,0 +1,176 @@ +/* + This file is part of GNUnet. + Copyright (C) 2020 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 <http://www.gnu.org/licenses/>. + + SPDX-License-Identifier: AGPL3.0-or-later + */ + +/** + * Common buffer management functions. + * + * @author Florian Dold + */ + +#ifndef GNUNET_BUFFER_LIB_H +#define GNUNET_BUFFER_LIB_H + +/** + * Dynamically growing buffer. Can be used to construct + * strings and other objects with dynamic size. + * + * This structure should, in most cases, be stack-allocated and + * zero-initialized, like: + * + * struct GNUNET_Buffer my_buffer = { 0 }; + */ +struct GNUNET_Buffer +{ + /** + * Capacity of the buffer. + */ + size_t capacity; + + /** + * Current write position. + */ + size_t position; + + /** + * Backing memory. + */ + char *mem; + + /** + * Log a warning if the buffer is grown over its initially allocated capacity. + */ + int warn_grow; +}; + + +/** + * Initialize a buffer with the given capacity. + * + * When a buffer is allocated with this function, a warning is logged + * when the buffer exceeds the initial capacity. + * + * @param buf the buffer to initialize + * @param capacity the capacity (in bytes) to allocate for @a buf + */ +void +GNUNET_buffer_prealloc (struct GNUNET_Buffer *buf, size_t capacity); + + +/** + * Make sure that at least @a n bytes remaining in the buffer. + * + * @param buf buffer to potentially grow + * @param n number of bytes that should be available to write + */ +void +GNUNET_buffer_ensure_remaining (struct GNUNET_Buffer *buf, size_t n); + + +/** + * Write bytes to the buffer. + * + * Grows the buffer if necessary. + * + * @param buf buffer to write to + * @param data data to read from + * @param len number of bytes to copy from @a data to @a buf + * + */ +void +GNUNET_buffer_write (struct GNUNET_Buffer *buf, const char *data, size_t len); + + +/** + * Write a 0-terminated string to a buffer, excluding the 0-terminator. + * + * Grows the buffer if necessary. + * + * @param buf the buffer to write to + * @param str the string to write to @a buf + */ +void +GNUNET_buffer_write_str (struct GNUNET_Buffer *buf, const char *str); + + +/** + * Write a path component to a buffer, ensuring that + * there is exactly one slash between the previous contents + * of the buffer and the new string. + * + * @param buf buffer to write to + * @param str string containing the new path component + */ +void +GNUNET_buffer_write_path (struct GNUNET_Buffer *buf, const char *str); + + +/** + * Write a 0-terminated formatted string to a buffer, excluding the + * 0-terminator. + * + * Grows the buffer if necessary. + * + * @param buf the buffer to write to + * @param fmt format string + * @param ... format arguments + */ +void +GNUNET_buffer_write_fstr (struct GNUNET_Buffer *buf, const char *fmt, ...); + + +/** + * Write a 0-terminated formatted string to a buffer, excluding the + * 0-terminator. + * + * Grows the buffer if necessary. + * + * @param buf the buffer to write to + * @param fmt format string + * @param args format argument list + */ +void +GNUNET_buffer_write_vfstr (struct GNUNET_Buffer *buf, const char *fmt, va_list + args); + + +/** + * Clear the buffer and return the string it contained. + * The caller is responsible to eventually #GNUNET_free + * the returned string. + * + * The returned string is always 0-terminated. + * + * @param buf the buffer to reap the string from + * @returns the buffer contained in the string + */ +char * +GNUNET_buffer_reap_str (struct GNUNET_Buffer *buf); + + +/** + * Free the backing memory of the given buffer. + * Does not free the memory of the buffer control structure, + * which is typically stack-allocated. + */ +void +GNUNET_buffer_clear (struct GNUNET_Buffer *buf); + + +#endif diff --git a/src/include/gnunet_curl_lib.h b/src/include/gnunet_curl_lib.h index 48eb7e490..8e981e91e 100644 --- a/src/include/gnunet_curl_lib.h +++ b/src/include/gnunet_curl_lib.h @@ -164,7 +164,7 @@ GNUNET_CURL_perform (struct GNUNET_CURL_Context *ctx); /** - * Run the main event loop for the Taler interaction. + * Run the main event loop for the HTTP interaction. * * @param ctx the library context * @param rp parses the raw response returned from diff --git a/src/include/gnunet_gns_service.h b/src/include/gnunet_gns_service.h index 5d2b7246a..ef81e9a88 100644 --- a/src/include/gnunet_gns_service.h +++ b/src/include/gnunet_gns_service.h @@ -147,6 +147,31 @@ GNUNET_GNS_lookup (struct GNUNET_GNS_Handle *handle, /** + * Perform an asynchronous lookup operation on the GNS. + * + * @param handle handle to the GNS service + * @param name the name to look up (in UTF-8 encoding) + * @param zone zone to look in + * @param type the GNS record type to look for + * @param options local options for the lookup + * @param recursion_depth_limit maximum number of zones + * that the lookup may (still) traverse + * @param proc function to call on result + * @param proc_cls closure for @a proc + * @return handle to the queued request + */ +struct GNUNET_GNS_LookupRequest * +GNUNET_GNS_lookup_limited (struct GNUNET_GNS_Handle *handle, + const char *name, + const struct GNUNET_CRYPTO_EcdsaPublicKey *zone, + uint32_t type, + enum GNUNET_GNS_LocalOptions options, + uint16_t recursion_depth_limit, + GNUNET_GNS_LookupResultProcessor proc, + void *proc_cls); + + +/** * Cancel pending lookup request * * @param lr the lookup request to cancel diff --git a/src/include/gnunet_gnsrecord_lib.h b/src/include/gnunet_gnsrecord_lib.h index 3a49d98b9..797c71380 100644 --- a/src/include/gnunet_gnsrecord_lib.h +++ b/src/include/gnunet_gnsrecord_lib.h @@ -141,6 +141,17 @@ extern "C" { #define GNUNET_GNSRECORD_TYPE_RECLAIM_OIDC_REDIRECT 65553 /** + * Record type for reclaim identity attestation + */ +#define GNUNET_GNSRECORD_TYPE_RECLAIM_ATTEST_ATTR 65554 + +/** + * Record type for reclaim identity references + */ +#define GNUNET_GNSRECORD_TYPE_RECLAIM_REFERENCE 65555 + + +/** * Flags that can be set for a record. */ enum GNUNET_GNSRECORD_Flags diff --git a/src/include/gnunet_protocols.h b/src/include/gnunet_protocols.h index cd7cb50de..8091fb367 100644 --- a/src/include/gnunet_protocols.h +++ b/src/include/gnunet_protocols.h @@ -2714,6 +2714,14 @@ extern "C" { #define GNUNET_MESSAGE_TYPE_RECLAIM_ATTRIBUTE_DELETE 976 +#define GNUNET_MESSAGE_TYPE_RECLAIM_ATTESTATION_STORE 977 + +#define GNUNET_MESSAGE_TYPE_RECLAIM_ATTESTATION_DELETE 978 + +#define GNUNET_MESSAGE_TYPE_RECLAIM_ATTESTATION_RESULT 979 + +#define GNUNET_MESSAGE_TYPE_RECLAIM_REFERENCE_STORE 980 + /************************************************** * * ABD MESSAGE TYPES @@ -3301,6 +3309,9 @@ extern "C" { /** * Next available: 1500 */ +#define GNUNET_MESSAGE_TYPE_RECLAIM_REFERENCE_DELETE 1500 + +#define GNUNET_MESSAGE_TYPE_RECLAIM_REFERENCE_RESULT 1501 /** diff --git a/src/include/gnunet_reclaim_attribute_lib.h b/src/include/gnunet_reclaim_attribute_lib.h index 4563a5f67..004f2bd10 100644 --- a/src/include/gnunet_reclaim_attribute_lib.h +++ b/src/include/gnunet_reclaim_attribute_lib.h @@ -50,6 +50,15 @@ extern "C" { */ #define GNUNET_RECLAIM_ATTRIBUTE_TYPE_STRING 1 +/** +* No value attestation. +*/ +#define GNUNET_RECLAIM_ATTESTATION_TYPE_NONE 10 + +/** +* A JSON Web Token attestation. +*/ +#define GNUNET_RECLAIM_ATTESTATION_TYPE_JWT 11 /** * An attribute. @@ -67,9 +76,48 @@ struct GNUNET_RECLAIM_ATTRIBUTE_Claim uint32_t type; /** + * Flags + */ + uint32_t flag; + /** + * The name of the attribute. Note "name" must never be individually + * free'd + */ + const char *name; + + /** + * Number of bytes in @e data. + */ + size_t data_size; + + /** + * Binary value stored as attribute value. Note: "data" must never + * be individually 'malloc'ed, but instead always points into some + * existing data area. + */ + const void *data; +}; + +/** + * An attestation. + */ +struct GNUNET_RECLAIM_ATTESTATION_Claim +{ + /** + * ID + */ + uint64_t id; + + /** + * Type/Format of Claim + */ + uint32_t type; + + /** * Version */ uint32_t version; + /** * The name of the attribute. Note "name" must never be individually * free'd @@ -89,6 +137,33 @@ struct GNUNET_RECLAIM_ATTRIBUTE_Claim const void *data; }; +/** + * A reference to an Attestatiom. + */ +struct GNUNET_RECLAIM_ATTESTATION_REFERENCE +{ + /** + * ID + */ + uint64_t id; + + /** + * Referenced ID of Attestation + */ + uint64_t id_attest; + + /** + * The name of the attribute/attestation reference value. Note "name" must never be individually + * free'd + */ + const char *name; + + /** + * The name of the attribute/attestation reference value. Note "name" must never be individually + * free'd + */ + const char *reference_value; +}; /** * A list of GNUNET_RECLAIM_ATTRIBUTE_Claim structures. @@ -123,6 +198,20 @@ struct GNUNET_RECLAIM_ATTRIBUTE_ClaimListEntry * The attribute claim */ struct GNUNET_RECLAIM_ATTRIBUTE_Claim *claim; + /** + * The attestation claim + */ + struct GNUNET_RECLAIM_ATTESTATION_Claim *attest; + + /** + * The reference + */ + struct GNUNET_RECLAIM_ATTESTATION_REFERENCE *reference; +}; + +struct GNUNET_RECLAIM_ATTRIBUTE_ClaimListEntryType +{ + uint32_t type; }; @@ -203,6 +292,14 @@ GNUNET_RECLAIM_ATTRIBUTE_list_serialize ( struct GNUNET_RECLAIM_ATTRIBUTE_ClaimList * GNUNET_RECLAIM_ATTRIBUTE_list_deserialize (const char *data, size_t data_size); +/** + * Count attestations in claim list + * + * @param attrs list + */ +int +GNUNET_RECLAIM_ATTRIBUTE_list_count_attest ( + const struct GNUNET_RECLAIM_ATTRIBUTE_ClaimList *attrs); /** * Get required size for serialization buffer @@ -299,6 +396,154 @@ GNUNET_RECLAIM_ATTRIBUTE_value_to_string (uint32_t type, const char * GNUNET_RECLAIM_ATTRIBUTE_number_to_typename (uint32_t type); +/** + * Get required size for serialization buffer + * FIXME: + * 1. The naming convention is violated here. + * It should GNUNET_RECLAIM_ATTRIBUTE_<lowercase from here>. + * It might make sense to refactor attestations into a separate folder. + * 2. The struct should be called GNUNET_RECLAIM_ATTESTATION_Data or + * GNUNET_RECLAIM_ATTRIBUTE_Attestation depending on location in source. + * + * @param attr the attestation to serialize + * @return the required buffer size + */ +size_t +GNUNET_RECLAIM_ATTESTATION_serialize_get_size ( + const struct GNUNET_RECLAIM_ATTESTATION_Claim *attr); + + +/** + * Serialize an attestation + * + * @param attr the attestation to serialize + * @param result the serialized attestation + * @return length of serialized data + */ +size_t +GNUNET_RECLAIM_ATTESTATION_serialize ( + const struct GNUNET_RECLAIM_ATTESTATION_Claim *attr, + char *result); + + +/** + * Deserialize an attestation + * + * @param data the serialized attestation + * @param data_size the length of the serialized data + * + * @return a GNUNET_IDENTITY_PROVIDER_Attribute, must be free'd by caller + */ +struct GNUNET_RECLAIM_ATTESTATION_Claim * +GNUNET_RECLAIM_ATTESTATION_deserialize (const char *data, size_t data_size); + + +/** + * Create a new attestation. + * + * @param attr_name the attestation name + * @param type the attestation type + * @param data the attestation value + * @param data_size the attestation value size + * @return the new attestation + */ +struct GNUNET_RECLAIM_ATTESTATION_Claim * +GNUNET_RECLAIM_ATTESTATION_claim_new (const char *attr_name, + uint32_t type, + const void *data, + size_t data_size); + +/** + * Convert the 'claim' of an attestation to a string + * + * @param type the type of attestation + * @param data claim in binary encoding + * @param data_size number of bytes in @a data + * @return NULL on error, otherwise human-readable representation of the claim + */ +char * +GNUNET_RECLAIM_ATTESTATION_value_to_string (uint32_t type, + const void *data, + size_t data_size); + +/** + * Convert human-readable version of a 'claim' of an attestation to the binary + * representation + * + * @param type type of the claim + * @param s human-readable string + * @param data set to value in binary encoding (will be allocated) + * @param data_size set to number of bytes in @a data + * @return #GNUNET_OK on success + */ +int +GNUNET_RECLAIM_ATTESTATION_string_to_value (uint32_t type, + const char *s, + void **data, + size_t *data_size); + +/** + * Convert an attestation type number to the corresponding attestation type string + * + * @param type number of a type + * @return corresponding typestring, NULL on error + */ +const char * +GNUNET_RECLAIM_ATTESTATION_number_to_typename (uint32_t type); + +/** + * Convert an attestation type name to the corresponding number + * + * @param typename name to convert + * @return corresponding number, UINT32_MAX on error + */ +uint32_t +GNUNET_RECLAIM_ATTESTATION_typename_to_number (const char *typename); + +/** + * Create a new attestation reference. + * + * @param attr_name the referenced claim name + * @param ref_value the claim name in the attestation + * @return the new reference + */ +struct GNUNET_RECLAIM_ATTESTATION_REFERENCE * +GNUNET_RECLAIM_ATTESTATION_reference_new (const char *attr_name, + const char *ref_value); + + +/** + * Get required size for serialization buffer + * + * @param attr the reference to serialize + * @return the required buffer size + */ +size_t +GNUNET_RECLAIM_ATTESTATION_REF_serialize_get_size ( + const struct GNUNET_RECLAIM_ATTESTATION_REFERENCE *attr); + +/** + * Serialize a reference + * + * @param attr the reference to serialize + * @param result the serialized reference + * @return length of serialized data + */ +size_t +GNUNET_RECLAIM_ATTESTATION_REF_serialize ( + const struct GNUNET_RECLAIM_ATTESTATION_REFERENCE *attr, + char *result); + +/** + * Deserialize a reference + * + * @param data the serialized reference + * @param data_size the length of the serialized data + * + * @return a GNUNET_IDENTITY_PROVIDER_Attribute, must be free'd by caller + */ +struct GNUNET_RECLAIM_ATTESTATION_REFERENCE * +GNUNET_RECLAIM_ATTESTATION_REF_deserialize (const char *data, size_t data_size); #if 0 /* keep Emacsens' auto-indent happy */ { diff --git a/src/include/gnunet_reclaim_attribute_plugin.h b/src/include/gnunet_reclaim_attribute_plugin.h index 26a4bb4f2..e61cca5b2 100644 --- a/src/include/gnunet_reclaim_attribute_plugin.h +++ b/src/include/gnunet_reclaim_attribute_plugin.h @@ -134,6 +134,33 @@ struct GNUNET_RECLAIM_ATTRIBUTE_PluginFunctions * Number to typename. */ GNUNET_RECLAIM_ATTRIBUTE_NumberToTypenameFunction number_to_typename; + + /** + * FIXME: It is odd that attestation functions are withing the attribute + * plugin. An attribute type may be backed by an attestation, but not + * necessarily. + * Maybe it would make more sense to refactor this into an attestation + * plugin? + * + * Attestation Conversion to string. + */ + GNUNET_RECLAIM_ATTRIBUTE_ValueToStringFunction value_to_string_attest; + + /** + * Attestation Conversion to binary. + */ + GNUNET_RECLAIM_ATTRIBUTE_StringToValueFunction string_to_value_attest; + + /** + * Attestation Typename to number. + */ + GNUNET_RECLAIM_ATTRIBUTE_TypenameToNumberFunction typename_to_number_attest; + + /** + * Attestation Number to typename. + */ + GNUNET_RECLAIM_ATTRIBUTE_NumberToTypenameFunction number_to_typename_attest; + }; diff --git a/src/include/gnunet_reclaim_service.h b/src/include/gnunet_reclaim_service.h index 237d791d9..214cdba69 100644 --- a/src/include/gnunet_reclaim_service.h +++ b/src/include/gnunet_reclaim_service.h @@ -117,7 +117,9 @@ typedef void (*GNUNET_RECLAIM_ContinuationWithStatus) (void *cls, */ typedef void (*GNUNET_RECLAIM_AttributeResult) ( void *cls, const struct GNUNET_CRYPTO_EcdsaPublicKey *identity, - const struct GNUNET_RECLAIM_ATTRIBUTE_Claim *attr); + const struct GNUNET_RECLAIM_ATTRIBUTE_Claim *attr, + const struct GNUNET_RECLAIM_ATTESTATION_Claim *attest, + const struct GNUNET_RECLAIM_ATTESTATION_REFERENCE *reference); /** @@ -152,6 +154,28 @@ GNUNET_RECLAIM_attribute_store ( /** + * Store an attestation. If the attestation is already present, + * it is replaced with the new attestation. + * + * @param h handle to the re:claimID service + * @param pkey private key of the identity + * @param attr the attestation value + * @param exp_interval the relative expiration interval for the attestation + * @param cont continuation to call when done + * @param cont_cls closure for @a cont + * @return handle to abort the request + */ +struct GNUNET_RECLAIM_Operation * +GNUNET_RECLAIM_attestation_store ( + struct GNUNET_RECLAIM_Handle *h, + const struct GNUNET_CRYPTO_EcdsaPrivateKey *pkey, + const struct GNUNET_RECLAIM_ATTESTATION_Claim *attr, + const struct GNUNET_TIME_Relative *exp_interval, + GNUNET_RECLAIM_ContinuationWithStatus cont, + void *cont_cls); + + +/** * Delete an attribute. Tickets used to share this attribute are updated * accordingly. * @@ -169,8 +193,44 @@ GNUNET_RECLAIM_attribute_delete ( const struct GNUNET_RECLAIM_ATTRIBUTE_Claim *attr, GNUNET_RECLAIM_ContinuationWithStatus cont, void *cont_cls); +/** + * Delete an attestation. Tickets used to share this attestation are updated + * accordingly. + * + * @param h handle to the re:claimID service + * @param pkey Private key of the identity to add an attribute to + * @param attr The attestation + * @param cont Continuation to call when done + * @param cont_cls Closure for @a cont + * @return handle Used to to abort the request + */ +struct GNUNET_RECLAIM_Operation * +GNUNET_RECLAIM_attestation_delete ( + struct GNUNET_RECLAIM_Handle *h, + const struct GNUNET_CRYPTO_EcdsaPrivateKey *pkey, + const struct GNUNET_RECLAIM_ATTESTATION_Claim *attr, + GNUNET_RECLAIM_ContinuationWithStatus cont, + void *cont_cls); /** + * Delete an attestation reference. Tickets used to share this reference are updated + * accordingly. + * + * @param h handle to the re:claimID service + * @param pkey Private key of the identity to delete the reference from + * @param attr The reference + * @param cont Continuation to call when done + * @param cont_cls Closure for @a cont + * @return handle Used to to abort the request + */ +struct GNUNET_RECLAIM_Operation * +GNUNET_RECLAIM_attestation_reference_delete ( + struct GNUNET_RECLAIM_Handle *h, + const struct GNUNET_CRYPTO_EcdsaPrivateKey *pkey, + const struct GNUNET_RECLAIM_ATTESTATION_REFERENCE *attr, + GNUNET_RECLAIM_ContinuationWithStatus cont, + void *cont_cls); +/** * List all attributes for a local identity. * This MUST lock the `struct GNUNET_RECLAIM_Handle` * for any other calls than #GNUNET_RECLAIM_get_attributes_next() and @@ -202,6 +262,26 @@ GNUNET_RECLAIM_get_attributes_start ( GNUNET_RECLAIM_AttributeResult proc, void *proc_cls, GNUNET_SCHEDULER_TaskCallback finish_cb, void *finish_cb_cls); +/** + * Store an attestation reference. If the reference is already present, + * it is replaced with the new reference. + * + * @param h handle to the re:claimID service + * @param pkey private key of the identity + * @param attr the reference value + * @param exp_interval the relative expiration interval for the reference + * @param cont continuation to call when done + * @param cont_cls closure for @a cont + * @return handle to abort the request + */ +struct GNUNET_RECLAIM_Operation * +GNUNET_RECLAIM_attestation_reference_store ( + struct GNUNET_RECLAIM_Handle *h, + const struct GNUNET_CRYPTO_EcdsaPrivateKey *pkey, + const struct GNUNET_RECLAIM_ATTESTATION_REFERENCE *attr, + const struct GNUNET_TIME_Relative *exp_interval, + GNUNET_RECLAIM_ContinuationWithStatus cont, + void *cont_cls); /** * Calls the record processor specified in #GNUNET_RECLAIM_get_attributes_start diff --git a/src/include/gnunet_util_taler_wallet_lib.h b/src/include/gnunet_util_taler_wallet_lib.h deleted file mode 100644 index a036824f6..000000000 --- a/src/include/gnunet_util_taler_wallet_lib.h +++ /dev/null @@ -1,56 +0,0 @@ -/* - This file is part of GNUnet - Copyright (C) 2009, 2015 GNUnet e.V. - - GNUnet is free software: you can redistribute it and/or modify it - under the terms of the GNU Affero General Public License as published - by the Free Software Foundation, either version 3 of the License, - or (at your option) any later version. - - GNUnet is distributed in the hope that it will be useful, but - WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - Affero General Public License for more details. - - You should have received a copy of the GNU Affero General Public License - along with this program. If not, see <http://www.gnu.org/licenses/>. - - SPDX-License-Identifier: AGPL3.0-or-later - */ - -/** - * @author Christian Grothoff - * - * @file - * Convenience header including all headers of subsystems in - * gnunet_util_taler_wallet library. Note that (due to the structure of the - * original headers), not all symbols declared by the included headers are - * actually included in the gnunet_util_taler_wallet library! The library - * excludes anything relating to the GNUnet installation location, scheduler, - * networking or OS-specific logic that would not apply to Apps/Browser - * extensions. - */ - -#ifndef GNUNET_UTIL_TALER_WALLET_LIB_H -#define GNUNET_UTIL_TALER_WALLET_LIB_H - -#ifdef __cplusplus -extern "C" -{ -#if 0 /* keep Emacsens' auto-indent happy */ -} -#endif -#endif - -#include "gnunet_crypto_lib.h" -#include "gnunet_container_lib.h" -#include "gnunet_strings_lib.h" - -#if 0 /* keep Emacsens' auto-indent happy */ -{ -#endif -#ifdef __cplusplus -} -#endif - -#endif diff --git a/src/reclaim-attribute/plugin_reclaim_attribute_gnuid.c b/src/reclaim-attribute/plugin_reclaim_attribute_gnuid.c index bb60909d9..ade2a27bb 100644 --- a/src/reclaim-attribute/plugin_reclaim_attribute_gnuid.c +++ b/src/reclaim-attribute/plugin_reclaim_attribute_gnuid.c @@ -90,6 +90,63 @@ gnuid_string_to_value (void *cls, } } +/** + * Convert the 'value' of an attestation to a string. + * + * @param cls closure, unused + * @param type type of the attestation + * @param data value in binary encoding + * @param data_size number of bytes in @a data + * @return NULL on error, otherwise human-readable representation of the value + */ +static char * +gnuid_value_to_string_attest (void *cls, + uint32_t type, + const void *data, + size_t data_size) +{ + switch (type) + { + case GNUNET_RECLAIM_ATTESTATION_TYPE_JWT: + return GNUNET_strndup (data, data_size); + + default: + return NULL; + } +} + + +/** + * Convert human-readable version of a 'value' of an attestation to the binary + * representation. + * + * @param cls closure, unused + * @param type type of the attestation + * @param s human-readable string + * @param data set to value in binary encoding (will be allocated) + * @param data_size set to number of bytes in @a data + * @return #GNUNET_OK on success + */ +static int +gnuid_string_to_value_attest (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_ATTESTATION_TYPE_JWT: + *data = GNUNET_strdup (s); + *data_size = strlen (s); + return GNUNET_OK; + + default: + return GNUNET_SYSERR; + } +} /** * Mapping of attribute type numbers to human-readable @@ -102,6 +159,16 @@ static struct } gnuid_name_map[] = { { "STRING", GNUNET_RECLAIM_ATTRIBUTE_TYPE_STRING }, { NULL, UINT32_MAX } }; +/** + * Mapping of attestation type numbers to human-readable + * attestation type names. + */ +static struct +{ + const char *name; + uint32_t number; +} gnuid_attest_name_map[] = { { "JWT", GNUNET_RECLAIM_ATTESTATION_TYPE_JWT }, + { NULL, UINT32_MAX } }; /** * Convert a type name to the corresponding number. @@ -141,6 +208,44 @@ gnuid_number_to_typename (void *cls, uint32_t type) return gnuid_name_map[i].name; } +/** + * Convert a type name to the corresponding number. + * + * @param cls closure, unused + * @param gnuid_typename name to convert + * @return corresponding number, UINT32_MAX on error + */ +static uint32_t +gnuid_typename_to_number_attest (void *cls, const char *gnuid_typename) +{ + unsigned int i; + + i = 0; + while ((NULL != gnuid_attest_name_map[i].name) && + (0 != strcasecmp (gnuid_typename, gnuid_attest_name_map[i].name))) + i++; + return gnuid_attest_name_map[i].number; +} + +/** + * Convert a type number (i.e. 1) to the corresponding type string + * + * @param cls closure, unused + * @param type number of a type to convert + * @return corresponding typestring, NULL on error + */ +static const char * +gnuid_number_to_typename_attest (void *cls, uint32_t type) +{ + unsigned int i; + + i = 0; + while ((NULL != gnuid_attest_name_map[i].name) && (type != + gnuid_attest_name_map[i]. + number)) + i++; + return gnuid_attest_name_map[i].name; +} /** * Entry point for the plugin. @@ -158,6 +263,10 @@ libgnunet_plugin_reclaim_attribute_gnuid_init (void *cls) api->string_to_value = &gnuid_string_to_value; api->typename_to_number = &gnuid_typename_to_number; api->number_to_typename = &gnuid_number_to_typename; + api->value_to_string_attest = &gnuid_value_to_string_attest; + api->string_to_value_attest = &gnuid_string_to_value_attest; + api->typename_to_number_attest = &gnuid_typename_to_number_attest; + api->number_to_typename_attest = &gnuid_number_to_typename_attest; return api; } diff --git a/src/reclaim-attribute/reclaim_attribute.c b/src/reclaim-attribute/reclaim_attribute.c index b81394ad2..43199c108 100644 --- a/src/reclaim-attribute/reclaim_attribute.c +++ b/src/reclaim-attribute/reclaim_attribute.c @@ -217,6 +217,116 @@ GNUNET_RECLAIM_ATTRIBUTE_value_to_string (uint32_t type, return NULL; } +/** + * Convert an attestation type name to the corresponding number + * + * @param typename name to convert + * @return corresponding number, UINT32_MAX on error + */ +uint32_t +GNUNET_RECLAIM_ATTESTATION_typename_to_number (const char *typename) +{ + unsigned int i; + struct Plugin *plugin; + uint32_t ret; + init (); + for (i = 0; i < num_plugins; i++) + { + plugin = attr_plugins[i]; + if (UINT32_MAX != + (ret = plugin->api->typename_to_number_attest (plugin->api->cls, + typename))) + return ret; + } + return UINT32_MAX; +} + +/** + * Convert an attestation type number to the corresponding attestation type string + * + * @param type number of a type + * @return corresponding typestring, NULL on error + */ +const char * +GNUNET_RECLAIM_ATTESTATION_number_to_typename (uint32_t type) +{ + unsigned int i; + struct Plugin *plugin; + const char *ret; + + init (); + for (i = 0; i < num_plugins; i++) + { + plugin = attr_plugins[i]; + if (NULL != + (ret = plugin->api->number_to_typename_attest (plugin->api->cls, type))) + return ret; + } + return NULL; +} +/** + * Convert human-readable version of a 'claim' of an attestation to the binary + * representation + * + * @param type type of the claim + * @param s human-readable string + * @param data set to value in binary encoding (will be allocated) + * @param data_size set to number of bytes in @a data + * @return #GNUNET_OK on success + */ +int +GNUNET_RECLAIM_ATTESTATION_string_to_value (uint32_t type, + const char *s, + void **data, + size_t *data_size) +{ + unsigned int i; + struct Plugin *plugin; + + init (); + for (i = 0; i < num_plugins; i++) + { + plugin = attr_plugins[i]; + if (GNUNET_OK == plugin->api->string_to_value_attest (plugin->api->cls, + type, + s, + data, + data_size)) + return GNUNET_OK; + } + return GNUNET_SYSERR; +} + + +/** + * Convert the 'claim' of an attestation to a string + * + * @param type the type of attestation + * @param data claim in binary encoding + * @param data_size number of bytes in @a data + * @return NULL on error, otherwise human-readable representation of the claim + */ +char * +GNUNET_RECLAIM_ATTESTATION_value_to_string (uint32_t type, + const void *data, + size_t data_size) +{ + unsigned int i; + struct Plugin *plugin; + char *ret; + + init (); + for (i = 0; i < num_plugins; i++) + { + plugin = attr_plugins[i]; + if (NULL != (ret = plugin->api->value_to_string_attest (plugin->api->cls, + type, + data, + data_size))) + return ret; + } + return NULL; +} /** * Create a new attribute. @@ -243,6 +353,42 @@ GNUNET_RECLAIM_ATTRIBUTE_claim_new (const char *attr_name, + strlen (attr_name_tmp) + 1 + data_size); attr->type = type; attr->data_size = data_size; + attr->flag = 0; + write_ptr = (char *) &attr[1]; + GNUNET_memcpy (write_ptr, attr_name_tmp, strlen (attr_name_tmp) + 1); + attr->name = write_ptr; + write_ptr += strlen (attr->name) + 1; + GNUNET_memcpy (write_ptr, data, data_size); + attr->data = write_ptr; + GNUNET_free (attr_name_tmp); + return attr; +} + +/** + * Create a new attestation. + * + * @param attr_name the attestation name + * @param type the attestation type + * @param data the attestation value + * @param data_size the attestation value size + * @return the new attestation + */ +struct GNUNET_RECLAIM_ATTESTATION_Claim * +GNUNET_RECLAIM_ATTESTATION_claim_new (const char *attr_name, + uint32_t type, + const void *data, + size_t data_size) +{ + struct GNUNET_RECLAIM_ATTESTATION_Claim *attr; + char *write_ptr; + char *attr_name_tmp = GNUNET_strdup (attr_name); + + GNUNET_STRINGS_utf8_tolower (attr_name, attr_name_tmp); + + attr = GNUNET_malloc (sizeof(struct GNUNET_RECLAIM_ATTESTATION_Claim) + + strlen (attr_name_tmp) + 1 + data_size); + attr->type = type; + attr->data_size = data_size; attr->version = 0; write_ptr = (char *) &attr[1]; GNUNET_memcpy (write_ptr, attr_name_tmp, strlen (attr_name_tmp) + 1); @@ -254,6 +400,40 @@ GNUNET_RECLAIM_ATTRIBUTE_claim_new (const char *attr_name, return attr; } +/** + * Create a new attestation reference. + * + * @param attr_name the referenced claim name + * @param ref_value the claim name in the attestation + * @return the new reference + */ +struct GNUNET_RECLAIM_ATTESTATION_REFERENCE * +GNUNET_RECLAIM_ATTESTATION_reference_new (const char *attr_name, + const char *ref_value) +{ + struct GNUNET_RECLAIM_ATTESTATION_REFERENCE *attr; + char *write_ptr; + char *attr_name_tmp = GNUNET_strdup (attr_name); + char *ref_value_tmp = GNUNET_strdup (ref_value); + + GNUNET_STRINGS_utf8_tolower (attr_name, attr_name_tmp); + GNUNET_STRINGS_utf8_tolower (ref_value, ref_value_tmp); + + attr = GNUNET_malloc (sizeof(struct GNUNET_RECLAIM_ATTESTATION_REFERENCE) + + strlen (attr_name_tmp) + strlen (ref_value_tmp) + 2); + + write_ptr = (char *) &attr[1]; + GNUNET_memcpy (write_ptr, attr_name_tmp, strlen (attr_name_tmp) + 1); + attr->name = write_ptr; + + write_ptr += strlen (attr_name) + 1; + GNUNET_memcpy (write_ptr, ref_value_tmp, strlen (ref_value_tmp) + 1); + attr->reference_value = write_ptr; + + GNUNET_free (attr_name_tmp); + GNUNET_free (ref_value_tmp); + return attr; +} /** * Add a new attribute to a claim list @@ -296,7 +476,30 @@ GNUNET_RECLAIM_ATTRIBUTE_list_serialize_get_size ( size_t len = 0; for (le = attrs->list_head; NULL != le; le = le->next) - len += GNUNET_RECLAIM_ATTRIBUTE_serialize_get_size (le->claim); + { + if (NULL != le->claim) + { + len += sizeof(struct GNUNET_RECLAIM_ATTRIBUTE_ClaimListEntryType); + len += GNUNET_RECLAIM_ATTRIBUTE_serialize_get_size (le->claim); + } + else if (NULL != le->attest ) + { + len += sizeof(struct GNUNET_RECLAIM_ATTRIBUTE_ClaimListEntryType); + len += GNUNET_RECLAIM_ATTESTATION_serialize_get_size (le->attest); + } + else if (NULL != le->reference) + { + len += sizeof(struct GNUNET_RECLAIM_ATTRIBUTE_ClaimListEntryType); + len += GNUNET_RECLAIM_ATTESTATION_REF_serialize_get_size (le->reference); + } + else + { + GNUNET_log (GNUNET_ERROR_TYPE_ERROR, + "Unserialized Claim List Entry Type for size not known.\n"); + break; + } + len += sizeof(struct GNUNET_RECLAIM_ATTRIBUTE_ClaimListEntry); + } return len; } @@ -317,14 +520,50 @@ GNUNET_RECLAIM_ATTRIBUTE_list_serialize ( size_t len; size_t total_len; char *write_ptr; - write_ptr = result; total_len = 0; for (le = attrs->list_head; NULL != le; le = le->next) { - len = GNUNET_RECLAIM_ATTRIBUTE_serialize (le->claim, write_ptr); - total_len += len; - write_ptr += len; + struct GNUNET_RECLAIM_ATTRIBUTE_ClaimListEntryType *list_type; + if (NULL != le->claim) + { + list_type = (struct + GNUNET_RECLAIM_ATTRIBUTE_ClaimListEntryType *) write_ptr; + list_type->type = htons (1); + total_len += sizeof(struct GNUNET_RECLAIM_ATTRIBUTE_ClaimListEntryType); + write_ptr += sizeof(struct GNUNET_RECLAIM_ATTRIBUTE_ClaimListEntryType); + len = GNUNET_RECLAIM_ATTRIBUTE_serialize (le->claim, write_ptr); + total_len += len; + write_ptr += len; + } + else if (NULL != le->attest ) + { + list_type = (struct + GNUNET_RECLAIM_ATTRIBUTE_ClaimListEntryType *) write_ptr; + list_type->type = htons (2); + total_len += sizeof(struct GNUNET_RECLAIM_ATTRIBUTE_ClaimListEntryType); + write_ptr += sizeof(struct GNUNET_RECLAIM_ATTRIBUTE_ClaimListEntryType); + len = GNUNET_RECLAIM_ATTESTATION_serialize (le->attest, write_ptr); + total_len += len; + write_ptr += len; + } + else if (NULL != le->reference) + { + list_type = (struct + GNUNET_RECLAIM_ATTRIBUTE_ClaimListEntryType *) write_ptr; + list_type->type = htons (3); + total_len += sizeof(struct GNUNET_RECLAIM_ATTRIBUTE_ClaimListEntryType); + write_ptr += sizeof(struct GNUNET_RECLAIM_ATTRIBUTE_ClaimListEntryType); + len = GNUNET_RECLAIM_ATTESTATION_REF_serialize (le->reference, write_ptr); + total_len += len; + write_ptr += len; + } + else + { + GNUNET_log (GNUNET_ERROR_TYPE_ERROR, + "Unserialized Claim List Entry Type not known.\n"); + continue; + } } return total_len; } @@ -345,23 +584,75 @@ GNUNET_RECLAIM_ATTRIBUTE_list_deserialize (const char *data, size_t data_size) size_t attr_len; const char *read_ptr; - if (data_size < sizeof(struct Attribute)) + if ((data_size < sizeof(struct Attribute) + sizeof(struct + GNUNET_RECLAIM_ATTRIBUTE_ClaimListEntry)) + && (data_size < sizeof(struct + Attestation) + + sizeof(struct GNUNET_RECLAIM_ATTRIBUTE_ClaimListEntry)) && + (data_size < sizeof(struct Attestation_Reference) + sizeof(struct + GNUNET_RECLAIM_ATTRIBUTE_ClaimListEntry)) ) return NULL; attrs = GNUNET_new (struct GNUNET_RECLAIM_ATTRIBUTE_ClaimList); read_ptr = data; while (((data + data_size) - read_ptr) >= sizeof(struct Attribute)) { - le = GNUNET_new (struct GNUNET_RECLAIM_ATTRIBUTE_ClaimListEntry); - le->claim = - GNUNET_RECLAIM_ATTRIBUTE_deserialize (read_ptr, - data_size - (read_ptr - data)); - GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, - "Deserialized attribute %s\n", - le->claim->name); - GNUNET_CONTAINER_DLL_insert (attrs->list_head, attrs->list_tail, le); - attr_len = GNUNET_RECLAIM_ATTRIBUTE_serialize_get_size (le->claim); - read_ptr += attr_len; + struct GNUNET_RECLAIM_ATTRIBUTE_ClaimListEntryType *list_type; + list_type = (struct GNUNET_RECLAIM_ATTRIBUTE_ClaimListEntryType *) read_ptr; + if (1 == ntohs (list_type->type)) + { + le = GNUNET_new (struct GNUNET_RECLAIM_ATTRIBUTE_ClaimListEntry); + read_ptr += sizeof(struct GNUNET_RECLAIM_ATTRIBUTE_ClaimListEntryType); + if (((data + data_size) - read_ptr) < sizeof(struct Attribute)) + break; + le->attest = NULL; + le->reference = NULL; + le->claim = + GNUNET_RECLAIM_ATTRIBUTE_deserialize (read_ptr, + data_size - (read_ptr - data)); + GNUNET_CONTAINER_DLL_insert (attrs->list_head, attrs->list_tail, le); + attr_len = GNUNET_RECLAIM_ATTRIBUTE_serialize_get_size (le->claim); + read_ptr += attr_len; + } + else if (2 == ntohs (list_type->type)) + { + le = GNUNET_new (struct GNUNET_RECLAIM_ATTRIBUTE_ClaimListEntry); + read_ptr += sizeof(struct GNUNET_RECLAIM_ATTRIBUTE_ClaimListEntryType); + if (((data + data_size) - read_ptr) < sizeof(struct Attestation)) + break; + le->claim = NULL; + le->reference = NULL; + le->attest = + GNUNET_RECLAIM_ATTESTATION_deserialize (read_ptr, + data_size - (read_ptr - data)); + GNUNET_CONTAINER_DLL_insert (attrs->list_head, attrs->list_tail, le); + attr_len = GNUNET_RECLAIM_ATTESTATION_serialize_get_size (le->attest); + read_ptr += attr_len; + } + else if (3 == ntohs (list_type->type)) + { + le = GNUNET_new (struct GNUNET_RECLAIM_ATTRIBUTE_ClaimListEntry); + read_ptr += sizeof(struct GNUNET_RECLAIM_ATTRIBUTE_ClaimListEntryType); + if (((data + data_size) - read_ptr) < sizeof(struct + Attestation_Reference)) + break; + le->claim = NULL; + le->attest = NULL; + le->reference = + GNUNET_RECLAIM_ATTESTATION_REF_deserialize (read_ptr, + data_size - (read_ptr + - data)); + GNUNET_CONTAINER_DLL_insert (attrs->list_head, attrs->list_tail, le); + attr_len = GNUNET_RECLAIM_ATTESTATION_REF_serialize_get_size ( + le->reference); + read_ptr += attr_len; + } + else + { + GNUNET_log (GNUNET_ERROR_TYPE_ERROR, + "Serialized Claim List Entry Type not known.\n"); + break; + } } return attrs; } @@ -381,16 +672,45 @@ GNUNET_RECLAIM_ATTRIBUTE_list_dup ( struct GNUNET_RECLAIM_ATTRIBUTE_ClaimList *result; result = GNUNET_new (struct GNUNET_RECLAIM_ATTRIBUTE_ClaimList); + if (NULL == attrs->list_head) + { + GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,"Duplicating empty List\n"); + } for (le = attrs->list_head; NULL != le; le = le->next) { result_le = GNUNET_new (struct GNUNET_RECLAIM_ATTRIBUTE_ClaimListEntry); - result_le->claim = - GNUNET_RECLAIM_ATTRIBUTE_claim_new (le->claim->name, - le->claim->type, - le->claim->data, - le->claim->data_size); - result_le->claim->version = le->claim->version; - result_le->claim->id = le->claim->id; + result_le->claim = NULL; + result_le->attest = NULL; + result_le->reference = NULL; + if (NULL != le->claim) + { + result_le->claim = + GNUNET_RECLAIM_ATTRIBUTE_claim_new (le->claim->name, + le->claim->type, + le->claim->data, + le->claim->data_size); + + result_le->claim->id = le->claim->id; + result_le->claim->flag = le->claim->flag; + } + if ( NULL != le->attest) + { + result_le->attest = GNUNET_RECLAIM_ATTESTATION_claim_new ( + le->attest->name, + le->attest->type, + le->attest->data, + le->attest-> + data_size); + result_le->attest->id = le->attest->id; + } + if (NULL !=le->reference) + { + result_le->reference = GNUNET_RECLAIM_ATTESTATION_reference_new ( + le->reference->name, + le->reference->reference_value); + result_le->reference->id = le->reference->id; + result_le->reference->id_attest = le->reference->id_attest; + } GNUNET_CONTAINER_DLL_insert (result->list_head, result->list_tail, result_le); @@ -411,9 +731,14 @@ GNUNET_RECLAIM_ATTRIBUTE_list_destroy ( struct GNUNET_RECLAIM_ATTRIBUTE_ClaimListEntry *le; struct GNUNET_RECLAIM_ATTRIBUTE_ClaimListEntry *tmp_le; - for (le = attrs->list_head; NULL != le;) + for (le = attrs->list_head; NULL != le; le = le->next) { - GNUNET_free (le->claim); + if (NULL != le->claim) + GNUNET_free (le->claim); + if (NULL != le->attest) + GNUNET_free (le->attest); + if (NULL != le->reference) + GNUNET_free (le->reference); tmp_le = le; le = le->next; GNUNET_free (tmp_le); @@ -421,7 +746,24 @@ GNUNET_RECLAIM_ATTRIBUTE_list_destroy ( GNUNET_free (attrs); } - +/** + * Count attestations in claim list + * + * @param attrs list + */ +int +GNUNET_RECLAIM_ATTRIBUTE_list_count_attest ( + const struct GNUNET_RECLAIM_ATTRIBUTE_ClaimList *attrs) +{ + struct GNUNET_RECLAIM_ATTRIBUTE_ClaimListEntry *le; + int i = 0; + for (le = attrs->list_head; NULL != le; le = le->next) + { + if (NULL != le->attest) + i++; + } + return i; +} /** * Get required size for serialization buffer * @@ -455,7 +797,7 @@ GNUNET_RECLAIM_ATTRIBUTE_serialize ( attr_ser = (struct Attribute *) result; attr_ser->attribute_type = htons (attr->type); - attr_ser->attribute_version = htonl (attr->version); + attr_ser->attribute_version = htonl (attr->flag); attr_ser->attribute_id = GNUNET_htonll (attr->id); name_len = strlen (attr->name); attr_ser->name_len = htons (name_len); @@ -505,7 +847,7 @@ GNUNET_RECLAIM_ATTRIBUTE_deserialize (const char *data, size_t data_size) attr = GNUNET_malloc (sizeof(struct GNUNET_RECLAIM_ATTRIBUTE_Claim) + data_len + name_len + 1); attr->type = ntohs (attr_ser->attribute_type); - attr->version = ntohl (attr_ser->attribute_version); + attr->flag = ntohl (attr_ser->attribute_version); attr->id = GNUNET_ntohll (attr_ser->attribute_id); attr->data_size = data_len; @@ -521,4 +863,193 @@ GNUNET_RECLAIM_ATTRIBUTE_deserialize (const char *data, size_t data_size) } +/** + * Get required size for serialization buffer + * + * @param attr the attestation to serialize + * @return the required buffer size + */ +size_t +GNUNET_RECLAIM_ATTESTATION_serialize_get_size ( + const struct GNUNET_RECLAIM_ATTESTATION_Claim *attr) +{ + return sizeof(struct Attestation) + strlen (attr->name) + attr->data_size; +} + +/** + * Serialize an attestation + * + * @param attr the attestation to serialize + * @param result the serialized attestation + * @return length of serialized data + */ +size_t +GNUNET_RECLAIM_ATTESTATION_serialize ( + const struct GNUNET_RECLAIM_ATTESTATION_Claim *attr, + char *result) +{ + size_t data_len_ser; + size_t name_len; + struct Attestation *attr_ser; + char *write_ptr; + + attr_ser = (struct Attestation *) result; + attr_ser->attestation_type = htons (attr->type); + attr_ser->attestation_version = htonl (attr->version); + attr_ser->attestation_id = GNUNET_htonll (attr->id); + name_len = strlen (attr->name); + attr_ser->name_len = htons (name_len); + write_ptr = (char *) &attr_ser[1]; + GNUNET_memcpy (write_ptr, attr->name, name_len); + write_ptr += name_len; + // TODO plugin-ize + // data_len_ser = plugin->serialize_attribute_value (attr, + // &attr_ser[1]); + data_len_ser = attr->data_size; + GNUNET_memcpy (write_ptr, attr->data, attr->data_size); + attr_ser->data_size = htons (data_len_ser); + + return sizeof(struct Attestation) + strlen (attr->name) + attr->data_size; +} + +/** + * Deserialize an attestation + * + * @param data the serialized attestation + * @param data_size the length of the serialized data + * + * @return a GNUNET_IDENTITY_PROVIDER_Attribute, must be free'd by caller + */ +struct GNUNET_RECLAIM_ATTESTATION_Claim * +GNUNET_RECLAIM_ATTESTATION_deserialize (const char *data, size_t data_size) +{ + struct GNUNET_RECLAIM_ATTESTATION_Claim *attr; + struct Attestation *attr_ser; + size_t data_len; + size_t name_len; + char *write_ptr; + + if (data_size < sizeof(struct Attestation)) + return NULL; + + attr_ser = (struct Attestation *) data; + data_len = ntohs (attr_ser->data_size); + name_len = ntohs (attr_ser->name_len); + if (data_size < sizeof(struct Attestation) + data_len + name_len) + { + GNUNET_log (GNUNET_ERROR_TYPE_ERROR, + "Buffer too small to deserialize\n"); + return NULL; + } + attr = GNUNET_malloc (sizeof(struct GNUNET_RECLAIM_ATTESTATION_Claim) + + data_len + name_len + 1); + attr->type = ntohs (attr_ser->attestation_type); + attr->version = ntohl (attr_ser->attestation_version); + attr->id = GNUNET_ntohll (attr_ser->attestation_id); + attr->data_size = data_len; + + write_ptr = (char *) &attr[1]; + GNUNET_memcpy (write_ptr, &attr_ser[1], name_len); + write_ptr[name_len] = '\0'; + attr->name = write_ptr; + + write_ptr += name_len + 1; + GNUNET_memcpy (write_ptr, (char *) &attr_ser[1] + name_len, attr->data_size); + attr->data = write_ptr; + return attr; +} + +/** + * Get required size for serialization buffer + * + * @param attr the reference to serialize + * @return the required buffer size + */ +size_t +GNUNET_RECLAIM_ATTESTATION_REF_serialize_get_size ( + const struct GNUNET_RECLAIM_ATTESTATION_REFERENCE *attr) +{ + return sizeof(struct Attestation_Reference) + strlen (attr->name) + strlen ( + attr->reference_value); +} + + +/** + * Serialize a reference + * + * @param attr the reference to serialize + * @param result the serialized reference + * @return length of serialized data + */ +size_t +GNUNET_RECLAIM_ATTESTATION_REF_serialize ( + const struct GNUNET_RECLAIM_ATTESTATION_REFERENCE *attr, + char *result) +{ + size_t name_len; + size_t refval_len; + struct Attestation_Reference *attr_ser; + char *write_ptr; + attr_ser = (struct Attestation_Reference *) result; + attr_ser->reference_id = GNUNET_htonll (attr->id); + attr_ser->attestation_id = GNUNET_htonll (attr->id_attest); + name_len = strlen (attr->name); + refval_len = strlen (attr->reference_value); + attr_ser->name_len = htons (name_len); + attr_ser->ref_value_len = htons (refval_len); + write_ptr = (char *) &attr_ser[1]; + GNUNET_memcpy (write_ptr, attr->name, name_len); + write_ptr += name_len; + GNUNET_memcpy (write_ptr, attr->reference_value, refval_len); + + return sizeof(struct Attestation_Reference) + strlen (attr->name) + strlen ( + attr->reference_value); +} + + +/** + * Deserialize a reference + * + * @param data the serialized reference + * @param data_size the length of the serialized data + * + * @return a GNUNET_IDENTITY_PROVIDER_Attribute, must be free'd by caller + */ +struct GNUNET_RECLAIM_ATTESTATION_REFERENCE * +GNUNET_RECLAIM_ATTESTATION_REF_deserialize (const char *data, size_t data_size) +{ + struct GNUNET_RECLAIM_ATTESTATION_REFERENCE *attr; + struct Attestation_Reference *attr_ser; + size_t name_len; + size_t refval_len; + char *write_ptr; + + if (data_size < sizeof(struct Attestation_Reference)) + return NULL; + attr_ser = (struct Attestation_Reference *) data; + name_len = ntohs (attr_ser->name_len); + refval_len = ntohs (attr_ser->ref_value_len); + if (data_size < sizeof(struct Attestation_Reference) + refval_len + name_len) + { + GNUNET_log (GNUNET_ERROR_TYPE_ERROR, + "Buffer too small to deserialize\n"); + return NULL; + } + attr = GNUNET_malloc (sizeof(struct GNUNET_RECLAIM_ATTESTATION_REFERENCE) + + refval_len + name_len + 2); + + attr->id = GNUNET_ntohll (attr_ser->reference_id); + attr->id_attest = GNUNET_ntohll (attr_ser->attestation_id); + + write_ptr = (char *) &attr[1]; + GNUNET_memcpy (write_ptr, &attr_ser[1], name_len); + write_ptr[name_len] = '\0'; + attr->name = write_ptr; + + write_ptr += name_len + 1; + GNUNET_memcpy (write_ptr, (char *) &attr_ser[1] + name_len, refval_len); + write_ptr[refval_len] = '\0'; + attr->reference_value = write_ptr; + return attr; +} /* end of reclaim_attribute.c */ diff --git a/src/reclaim-attribute/reclaim_attribute.h b/src/reclaim-attribute/reclaim_attribute.h index d7358847e..80f1e5aac 100644 --- a/src/reclaim-attribute/reclaim_attribute.h +++ b/src/reclaim-attribute/reclaim_attribute.h @@ -61,4 +61,66 @@ struct Attribute // followed by data_size Attribute value data }; +/** + * Serialized attestation claim + */ +struct Attestation +{ + /** + * Attestation type + */ + uint32_t attestation_type; + + /** + * Attestation version + */ + uint32_t attestation_version; + + /** + * Attestation ID + */ + uint64_t attestation_id; + + /** + * Name length + */ + uint32_t name_len; + + /** + * Data size + */ + uint32_t data_size; + + // followed by data_size Attestation value data +}; + +/** + * Serialized attestation reference + */ +struct Attestation_Reference +{ + /** + * Reference ID + */ + uint64_t reference_id; + + /** + * The ID of the referenced attestation + */ + uint64_t attestation_id; + + /** + * Claim Name length + */ + uint32_t name_len; + + /** + * Length of the referenced value + */ + uint32_t ref_value_len; + + + // followed by the name and referenced value +}; + #endif diff --git a/src/reclaim/gnunet-reclaim.c b/src/reclaim/gnunet-reclaim.c index 58f8cd6e2..5f9170f05 100644 --- a/src/reclaim/gnunet-reclaim.c +++ b/src/reclaim/gnunet-reclaim.c @@ -226,7 +226,9 @@ store_attr_cont (void *cls, int32_t success, const char *emsg) static void process_attrs (void *cls, const struct GNUNET_CRYPTO_EcdsaPublicKey *identity, - const struct GNUNET_RECLAIM_ATTRIBUTE_Claim *attr) + const struct GNUNET_RECLAIM_ATTRIBUTE_Claim *attr, + const struct GNUNET_RECLAIM_ATTESTATION_Claim *attest, + const struct GNUNET_RECLAIM_ATTESTATION_REFERENCE *reference) { char *value_str; char *id; @@ -253,7 +255,7 @@ process_attrs (void *cls, attr->name, value_str, attr_type, - attr->version, + attr->flag, id); GNUNET_free (id); } @@ -445,7 +447,9 @@ iter_finished (void *cls) static void iter_cb (void *cls, const struct GNUNET_CRYPTO_EcdsaPublicKey *identity, - const struct GNUNET_RECLAIM_ATTRIBUTE_Claim *attr) + const struct GNUNET_RECLAIM_ATTRIBUTE_Claim *attr, + const struct GNUNET_RECLAIM_ATTESTATION_Claim *attest, + const struct GNUNET_RECLAIM_ATTESTATION_REFERENCE *reference) { struct GNUNET_RECLAIM_ATTRIBUTE_ClaimListEntry *le; char *attrs_tmp; @@ -480,7 +484,7 @@ iter_cb (void *cls, attr->type, attr->data, attr->data_size); - le->claim->version = attr->version; + le->claim->flag = attr->flag; le->claim->id = attr->id; GNUNET_CONTAINER_DLL_insert (attr_list->list_head, attr_list->list_tail, @@ -514,7 +518,7 @@ iter_cb (void *cls, attr->name, attr_str, attr_type, - attr->version, + attr->flag, id); GNUNET_free (id); } diff --git a/src/reclaim/gnunet-service-reclaim.c b/src/reclaim/gnunet-service-reclaim.c index a83ea05a6..556006af0 100644 --- a/src/reclaim/gnunet-service-reclaim.c +++ b/src/reclaim/gnunet-service-reclaim.c @@ -266,6 +266,15 @@ struct AttributeDeleteHandle struct GNUNET_RECLAIM_ATTRIBUTE_Claim *claim; /** + * The attestation to delete + */ + struct GNUNET_RECLAIM_ATTESTATION_Claim *attest; + + /** + * The reference to delete + */ + struct GNUNET_RECLAIM_ATTESTATION_REFERENCE *reference; + /** * Tickets to update */ struct TicketRecordsEntry *tickets_to_update_head; @@ -328,6 +337,16 @@ struct AttributeStoreHandle struct GNUNET_RECLAIM_ATTRIBUTE_Claim *claim; /** + * The attestation to store + */ + struct GNUNET_RECLAIM_ATTESTATION_Claim *attest; + + /** + * The reference to store + */ + struct GNUNET_RECLAIM_ATTESTATION_REFERENCE *reference; + + /** * The attribute expiration interval */ struct GNUNET_TIME_Relative exp; @@ -459,6 +478,10 @@ cleanup_adh (struct AttributeDeleteHandle *adh) GNUNET_free (adh->label); if (NULL != adh->claim) GNUNET_free (adh->claim); + if (NULL != adh->attest) + GNUNET_free (adh->attest); + if (NULL != adh->reference) + GNUNET_free (adh->reference); while (NULL != (le = adh->tickets_to_update_head)) { GNUNET_CONTAINER_DLL_remove (adh->tickets_to_update_head, @@ -486,6 +509,10 @@ cleanup_as_handle (struct AttributeStoreHandle *ash) GNUNET_NAMESTORE_cancel (ash->ns_qe); if (NULL != ash->claim) GNUNET_free (ash->claim); + if (NULL != ash->attest) + GNUNET_free (ash->attest); + if (NULL != ash->reference) + GNUNET_free (ash->reference); GNUNET_free (ash); } @@ -1023,6 +1050,478 @@ handle_attribute_store_message (void *cls, /** + * Attestation store result handler + * + * @param cls our attribute store handle + * @param success GNUNET_OK if successful + * @param emsg error message (NULL if success=GNUNET_OK) + */ +static void +attest_store_cont (void *cls, int32_t success, const char *emsg) +{ + struct AttributeStoreHandle *ash = cls; + struct GNUNET_MQ_Envelope *env; + struct SuccessResultMessage *acr_msg; + + ash->ns_qe = NULL; + GNUNET_CONTAINER_DLL_remove (ash->client->store_op_head, + ash->client->store_op_tail, + ash); + + if (GNUNET_SYSERR == success) + { + GNUNET_log (GNUNET_ERROR_TYPE_ERROR, + "Failed to store attestation %s\n", + emsg); + cleanup_as_handle (ash); + GNUNET_SCHEDULER_add_now (&do_shutdown, NULL); + return; + } + + GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Sending SUCCESS_RESPONSE message\n"); + env = GNUNET_MQ_msg (acr_msg, GNUNET_MESSAGE_TYPE_RECLAIM_SUCCESS_RESPONSE); + acr_msg->id = htonl (ash->r_id); + acr_msg->op_result = htonl (GNUNET_OK); + GNUNET_MQ_send (ash->client->mq, env); + cleanup_as_handle (ash); +} + +/** + * Send a reference error response + * + * @param ash our attribute store handle + * @param success the success status + */ +static void +send_ref_error (struct AttributeStoreHandle *ash) +{ + struct GNUNET_MQ_Envelope *env; + struct SuccessResultMessage *acr_msg; + + ash->ns_qe = NULL; + GNUNET_CONTAINER_DLL_remove (ash->client->store_op_head, + ash->client->store_op_tail, + ash); + + GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Sending SUCCESS_RESPONSE message\n"); + env = GNUNET_MQ_msg (acr_msg, GNUNET_MESSAGE_TYPE_RECLAIM_SUCCESS_RESPONSE); + acr_msg->id = htonl (ash->r_id); + acr_msg->op_result = htonl (GNUNET_SYSERR); + GNUNET_MQ_send (ash->client->mq, env); + cleanup_as_handle (ash); +} + +/** + * Error looking up potential attestation. Abort. + * + * @param cls our attribute store handle + */ +static void +attest_error (void *cls) +{ + struct AttributeStoreHandle *ash = cls; + GNUNET_log (GNUNET_ERROR_TYPE_ERROR, + "Failed to check for existing Attestation\n"); + cleanup_as_handle (ash); + GNUNET_SCHEDULER_add_now (&do_shutdown, NULL); + return; +} + +/** +* Check for existing record before storing reference +* +* @param cls our attribute store handle +* @param zone zone we are iterating +* @param label label of the records +* @param rd_count record count +* @param rd records +*/ +static void +attest_add_cb (void *cls, + const struct GNUNET_CRYPTO_EcdsaPrivateKey *zone, + const char *label, + unsigned int rd_count, + const struct GNUNET_GNSRECORD_Data *rd) +{ + struct AttributeStoreHandle *ash = cls; + char *buf; + size_t buf_size; + buf_size = GNUNET_RECLAIM_ATTESTATION_serialize_get_size (ash->attest); + buf = GNUNET_malloc (buf_size); + GNUNET_RECLAIM_ATTESTATION_serialize (ash->attest, buf); + if (0 == rd_count ) + { + GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, + "Storing new Attestation\n"); + struct GNUNET_GNSRECORD_Data rd_new[1]; + rd_new[0].data_size = buf_size; + rd_new[0].data = buf; + rd_new[0].record_type = GNUNET_GNSRECORD_TYPE_RECLAIM_ATTEST_ATTR; + rd_new[0].flags = GNUNET_GNSRECORD_RF_RELATIVE_EXPIRATION; + rd_new[0].expiration_time = ash->exp.rel_value_us; + GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Encrypting with label %s\n", label); + ash->ns_qe = GNUNET_NAMESTORE_records_store (nsh, + &ash->identity, + label, + 1, + rd_new, + &attest_store_cont, + ash); + GNUNET_free (buf); + return; + } + if (GNUNET_GNSRECORD_TYPE_RECLAIM_ATTEST_ATTR != rd[0].record_type) + { + GNUNET_log (GNUNET_ERROR_TYPE_ERROR, + "Existing Attestation location is not an Attestation\n"); + send_ref_error (ash); + return; + } + struct GNUNET_GNSRECORD_Data rd_new[rd_count]; + for (int i = 0; i<rd_count; i++) + { + rd_new[i] = rd[i]; + } + rd_new[0].data_size = buf_size; + rd_new[0].data = buf; + rd_new[0].record_type = GNUNET_GNSRECORD_TYPE_RECLAIM_ATTEST_ATTR; + rd_new[0].flags = GNUNET_GNSRECORD_RF_RELATIVE_EXPIRATION; + rd_new[0].expiration_time = ash->exp.rel_value_us; + GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Encrypting with label %s\n", label); + ash->ns_qe = GNUNET_NAMESTORE_records_store (nsh, + &ash->identity, + label, + rd_count, + rd_new, + &attest_store_cont, + ash); + GNUNET_free (buf); +} + +/** + * Add a new attestation + * + * @param cls the AttributeStoreHandle + */ +static void +attest_store_task (void *cls) +{ + struct AttributeStoreHandle *ash = cls; + char *label; + + // Give the ash a new id if unset + if (0 == ash->attest->id) + ash->attest->id + = GNUNET_CRYPTO_random_u64 (GNUNET_CRYPTO_QUALITY_STRONG, UINT64_MAX); + label = GNUNET_STRINGS_data_to_string_alloc (&ash->attest->id, + sizeof(uint64_t)); + GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, + "Looking up existing data under label %s\n", label); +// Test for the content of the existing ID + ash->ns_qe = GNUNET_NAMESTORE_records_lookup (nsh, + &ash->identity, + label, + &attest_error, + ash, + &attest_add_cb, + ash); + GNUNET_free (label); +} + +/** + * Check an attestation store message + * + * @param cls unused + * @param sam the message to check + */ +static int +check_attestation_store_message (void *cls, + const struct AttributeStoreMessage *sam) +{ + uint16_t size; + + size = ntohs (sam->header.size); + if (size <= sizeof(struct AttributeStoreMessage)) + { + GNUNET_break (0); + return GNUNET_SYSERR; + } + return GNUNET_OK; +} + +/** +* Handle an attestation store message +* +* @param cls our client +* @param sam the message to handle +*/ +static void +handle_attestation_store_message (void *cls, + const struct AttributeStoreMessage *sam) +{ + struct AttributeStoreHandle *ash; + struct IdpClient *idp = cls; + size_t data_len; + + GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Received ATTESTATION_STORE message\n"); + + data_len = ntohs (sam->attr_len); + + ash = GNUNET_new (struct AttributeStoreHandle); + ash->attest = GNUNET_RECLAIM_ATTESTATION_deserialize ((char *) &sam[1], + data_len); + + ash->r_id = ntohl (sam->id); + ash->identity = sam->identity; + ash->exp.rel_value_us = GNUNET_ntohll (sam->exp); + GNUNET_CRYPTO_ecdsa_key_get_public (&sam->identity, &ash->identity_pkey); + + GNUNET_SERVICE_client_continue (idp->client); + ash->client = idp; + GNUNET_CONTAINER_DLL_insert (idp->store_op_head, idp->store_op_tail, ash); + GNUNET_SCHEDULER_add_now (&attest_store_task, ash); +} + +/** + * Error looking up potential reference value. Abort. + * + * @param cls our attribute store handle + */ +static void +ref_error (void *cls) +{ + struct AttributeStoreHandle *ash = cls; + GNUNET_log (GNUNET_ERROR_TYPE_ERROR, + "Failed to find Attestation entry for Attestation reference\n"); + cleanup_as_handle (ash); + GNUNET_SCHEDULER_add_now (&do_shutdown, NULL); + return; +} + +/** + * Error looking up potential reference value. Abort. + * + * @param cls our attribute delete handle + */ +static void +ref_del_error (void *cls) +{ + struct AttributeDeleteHandle *adh = cls; + GNUNET_log (GNUNET_ERROR_TYPE_ERROR, + "Failed to find Attestation entry for Attestation reference\n"); + cleanup_adh (adh); + GNUNET_SCHEDULER_add_now (&do_shutdown, NULL); + return; +} +/** +* Reference store result handler +* +* @param cls our attribute store handle +* @param success GNUNET_OK if successful +* @param emsg error message (NULL if success=GNUNET_OK) +*/ +static void +reference_store_cont (void *cls, int32_t success, const char *emsg) +{ + struct AttributeStoreHandle *ash = cls; + struct GNUNET_MQ_Envelope *env; + struct SuccessResultMessage *acr_msg; + + ash->ns_qe = NULL; + GNUNET_CONTAINER_DLL_remove (ash->client->store_op_head, + ash->client->store_op_tail, + ash); + + if (GNUNET_SYSERR == success) + { + GNUNET_log (GNUNET_ERROR_TYPE_ERROR, + "Failed to store reference %s\n", + emsg); + cleanup_as_handle (ash); + GNUNET_SCHEDULER_add_now (&do_shutdown, NULL); + return; + } + + GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Sending SUCCESS_RESPONSE message\n"); + env = GNUNET_MQ_msg (acr_msg, GNUNET_MESSAGE_TYPE_RECLAIM_SUCCESS_RESPONSE); + acr_msg->id = htonl (ash->r_id); + acr_msg->op_result = htonl (GNUNET_OK); + GNUNET_MQ_send (ash->client->mq, env); + cleanup_as_handle (ash); +} + + +/** +* Check for existing record before storing reference +* +* @param cls our attribute store handle +* @param zone zone we are iterating +* @param label label of the records +* @param rd_count record count +* @param rd records +*/ +static void +ref_add_cb (void *cls, + const struct GNUNET_CRYPTO_EcdsaPrivateKey *zone, + const char *label, + unsigned int rd_count, + const struct GNUNET_GNSRECORD_Data *rd) +{ + struct AttributeStoreHandle *ash = cls; + char *buf; + size_t buf_size; + buf_size = GNUNET_RECLAIM_ATTESTATION_REF_serialize_get_size (ash->reference); + buf = GNUNET_malloc (buf_size); + GNUNET_RECLAIM_ATTESTATION_REF_serialize (ash->reference, buf); + struct GNUNET_RECLAIM_ATTESTATION_REFERENCE *ref; + char *data_tmp; + if (0 == rd_count ) + { + GNUNET_log (GNUNET_ERROR_TYPE_ERROR, + "Failed to find Attestation entry for Attestation reference\n"); + send_ref_error (ash); + return; + } + if (GNUNET_GNSRECORD_TYPE_RECLAIM_ATTEST_ATTR != rd[0].record_type) + { + GNUNET_log (GNUNET_ERROR_TYPE_ERROR, + "Intended Reference storage location is not an attestation\n"); + send_ref_error (ash); + return; + } + struct GNUNET_GNSRECORD_Data rd_new[rd_count + 1]; + int i; + for (i = 0; i<rd_count; i++) + { + data_tmp = GNUNET_malloc (rd[i].data_size); + GNUNET_memcpy (data_tmp, rd[i].data, rd[i].data_size); + ref = GNUNET_RECLAIM_ATTESTATION_REF_deserialize (data_tmp, htons ( + rd[i].data_size)); + rd_new[i] = rd[i]; + if ((strcmp (ash->reference->name,ref->name) == 0)&& + (strcmp (ash->reference->reference_value,ref->reference_value)==0) ) + { + GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, + "Reference already stored\n"); + reference_store_cont (ash,GNUNET_OK, NULL); + return; + } + } + rd_new[rd_count].data_size = buf_size; + rd_new[rd_count].data = buf; + rd_new[rd_count].record_type = GNUNET_GNSRECORD_TYPE_RECLAIM_REFERENCE; + rd_new[rd_count].flags = GNUNET_GNSRECORD_RF_RELATIVE_EXPIRATION; + rd_new[rd_count].expiration_time = ash->exp.rel_value_us; + GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Encrypting with label %s\n", label); + ash->ns_qe = GNUNET_NAMESTORE_records_store (nsh, + &ash->identity, + label, + rd_count + 1, + rd_new, + &reference_store_cont, + ash); + GNUNET_free (buf); +} + +/** + * Add a new reference + * + * @param cls the AttributeStoreHandle + */ +static void +reference_store_task (void *cls) +{ + struct AttributeStoreHandle *ash = cls; + char *label; + + GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Storing reference\n"); + + // Give the ash a new id if unset + if (0 == ash->reference->id) + { + if (0 == ash->reference->id_attest) + { + ash->reference->id = GNUNET_CRYPTO_random_u64 ( + GNUNET_CRYPTO_QUALITY_STRONG, + UINT64_MAX); + } + else + { + ash->reference->id = ash->reference->id_attest; + } + } + + label = GNUNET_STRINGS_data_to_string_alloc (&ash->reference->id, + sizeof(uint64_t)); + GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, + "Looking up existing data under label %s\n", label); +// Test for the content of the existing ID + + ash->ns_qe = GNUNET_NAMESTORE_records_lookup (nsh, + &ash->identity, + label, + &ref_error, + ash, + &ref_add_cb, + ash); + GNUNET_free (label); +} + +/** + * Check an attestation reference store message + * + * @param cls unused + * @param sam the message to check + */ +static int +check_reference_store_message (void *cls, + const struct + AttributeStoreMessage *sam) +{ + uint16_t size; + + size = ntohs (sam->header.size); + if (size <= sizeof(struct AttributeStoreMessage)) + { + GNUNET_break (0); + return GNUNET_SYSERR; + } + return GNUNET_OK; +} + + +/** + * Handle an attestation reference store message + * + * @param cls our client + * @param sam the message to handle + */ +static void +handle_reference_store_message (void *cls, + const struct AttributeStoreMessage *sam) +{ + struct AttributeStoreHandle *ash; + struct IdpClient *idp = cls; + size_t data_len; + + GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Received REFERENCE_STORE message\n"); + + data_len = ntohs (sam->attr_len); + ash = GNUNET_new (struct AttributeStoreHandle); + ash->reference = GNUNET_RECLAIM_ATTESTATION_REF_deserialize ((char *) &sam[1], + data_len); + ash->r_id = ntohl (sam->id); + ash->identity = sam->identity; + ash->exp.rel_value_us = GNUNET_ntohll (sam->exp); + GNUNET_CRYPTO_ecdsa_key_get_public (&sam->identity, &ash->identity_pkey); + + + GNUNET_SERVICE_client_continue (idp->client); + ash->client = idp; + GNUNET_CONTAINER_DLL_insert (idp->store_op_head, idp->store_op_tail, ash); + GNUNET_SCHEDULER_add_now (&reference_store_task, ash); +} +/** * Send a deletion success response * * @param adh our attribute deletion handle @@ -1066,15 +1565,21 @@ ticket_iter (void *cls, struct AttributeDeleteHandle *adh = cls; struct TicketRecordsEntry *le; int has_changed = GNUNET_NO; - for (int i = 0; i < rd_count; i++) { if (GNUNET_GNSRECORD_TYPE_RECLAIM_ATTR_REF != rd[i].record_type) continue; - if (0 != memcmp (rd[i].data, &adh->claim->id, sizeof(uint64_t))) - continue; + if (adh->claim != NULL) + if (0 != memcmp (rd[i].data, &adh->claim->id, sizeof(uint64_t))) + continue; + if (adh->attest != NULL) + if (0 != memcmp (rd[i].data, &adh->attest->id, sizeof(uint64_t))) + continue; + if (adh->reference != NULL) + if (0 != memcmp (rd[i].data, &adh->reference->id, sizeof(uint64_t))) + continue; GNUNET_log (GNUNET_ERROR_TYPE_ERROR, - "Attribute to delete found (%s)\n", + "Attribute or Attestation/Reference to delete found (%s)\n", adh->label); has_changed = GNUNET_YES; break; @@ -1136,7 +1641,7 @@ update_tickets (void *cls) if (NULL == adh->tickets_to_update_head) { GNUNET_log (GNUNET_ERROR_TYPE_ERROR, - "Finished updatding tickets, success\n"); + "Finished updating tickets, success\n"); send_delete_response (adh, GNUNET_OK); cleanup_adh (adh); return; @@ -1164,9 +1669,18 @@ update_tickets (void *cls) int j = 0; for (int i = 0; i < le->rd_count; i++) { - if ((GNUNET_GNSRECORD_TYPE_RECLAIM_ATTR_REF == rd[i].record_type) - && (0 == memcmp (rd[i].data, &adh->claim->id, sizeof(uint64_t)))) - continue; + if (adh->claim != NULL) + if ((GNUNET_GNSRECORD_TYPE_RECLAIM_ATTR_REF == rd[i].record_type) + && (0 == memcmp (rd[i].data, &adh->claim->id, sizeof(uint64_t)))) + continue; + if (adh->attest != NULL) + if ((GNUNET_GNSRECORD_TYPE_RECLAIM_ATTR_REF == rd[i].record_type) + && (0 == memcmp (rd[i].data, &adh->attest->id, sizeof(uint64_t)))) + continue; + if (adh->reference != NULL) + if ((GNUNET_GNSRECORD_TYPE_RECLAIM_ATTR_REF == rd[i].record_type) + && (0 == memcmp (rd[i].data, &adh->reference->id, sizeof(uint64_t)))) + continue; rd_new[j] = rd[i]; j++; } @@ -1192,7 +1706,6 @@ static void ticket_iter_fin (void *cls) { struct AttributeDeleteHandle *adh = cls; - adh->ns_it = NULL; GNUNET_SCHEDULER_add_now (&update_tickets, adh); } @@ -1309,6 +1822,8 @@ handle_attribute_delete_message (void *cls, adh = GNUNET_new (struct AttributeDeleteHandle); adh->claim = GNUNET_RECLAIM_ATTRIBUTE_deserialize ((char *) &dam[1], data_len); + adh->reference = NULL; + adh->attest = NULL; adh->r_id = ntohl (dam->id); adh->identity = dam->identity; @@ -1326,6 +1841,256 @@ handle_attribute_delete_message (void *cls, adh); } +/** + * Attestation deleted callback + * + * @param cls our handle + * @param success success status + * @param emsg error message (NULL if success=GNUNET_OK) + */ +static void +attest_delete_cont (void *cls, int32_t success, const char *emsg) +{ + struct AttributeDeleteHandle *adh = cls; + + adh->ns_qe = NULL; + if (GNUNET_SYSERR == success) + { + GNUNET_log (GNUNET_ERROR_TYPE_ERROR, + "Error deleting attestation %s\n", + adh->label); + send_delete_response (adh, GNUNET_SYSERR); + cleanup_adh (adh); + return; + } + GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Updating tickets...\n"); + GNUNET_SCHEDULER_add_now (&start_ticket_update, adh); +} + +/** + * Check attestation delete message format + * + * @cls unused + * @dam message to check + */ +static int +check_attestation_delete_message (void *cls, + const struct AttributeDeleteMessage *dam) +{ + uint16_t size; + + size = ntohs (dam->header.size); + if (size <= sizeof(struct AttributeDeleteMessage)) + { + GNUNET_break (0); + return GNUNET_SYSERR; + } + return GNUNET_OK; +} + + +/** + * Handle attestation deletion + * + * @param cls our client + * @param dam deletion message + */ +static void +handle_attestation_delete_message (void *cls, + const struct AttributeDeleteMessage *dam) +{ + struct AttributeDeleteHandle *adh; + struct IdpClient *idp = cls; + size_t data_len; + + GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Received ATTESTATION_DELETE message\n"); + + data_len = ntohs (dam->attr_len); + + adh = GNUNET_new (struct AttributeDeleteHandle); + adh->attest = GNUNET_RECLAIM_ATTESTATION_deserialize ((char *) &dam[1], + data_len); + adh->reference = NULL; + adh->claim = NULL; + + adh->r_id = ntohl (dam->id); + adh->identity = dam->identity; + adh->label + = GNUNET_STRINGS_data_to_string_alloc (&adh->attest->id, sizeof(uint64_t)); + GNUNET_SERVICE_client_continue (idp->client); + adh->client = idp; + GNUNET_CONTAINER_DLL_insert (idp->delete_op_head, idp->delete_op_tail, adh); + adh->ns_qe = GNUNET_NAMESTORE_records_store (nsh, + &adh->identity, + adh->label, + 0, + NULL, + &attest_delete_cont, + adh); +} + + + +/** +* Reference deleted callback +* +* @param cls our handle +* @param success success status +* @param emsg error message (NULL if success=GNUNET_OK) +*/ +static void +reference_delete_cont (void *cls, int32_t success, const char *emsg) +{ + struct AttributeDeleteHandle *adh = cls; + + adh->ns_qe = NULL; + if (GNUNET_SYSERR == success) + { + GNUNET_log (GNUNET_ERROR_TYPE_ERROR, + "Error deleting reference %s\n", + adh->label); + send_delete_response (adh, GNUNET_SYSERR); + cleanup_adh (adh); + return; + } + GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Updating tickets...\n"); + //GNUNET_SCHEDULER_add_now (&start_ticket_update, adh); + send_delete_response (adh, GNUNET_OK); + cleanup_adh (adh); + return; +} + +static void +ref_del_cb (void *cls, + const struct GNUNET_CRYPTO_EcdsaPrivateKey *zone, + const char *label, + unsigned int rd_count, + const struct GNUNET_GNSRECORD_Data *rd) +{ + + struct AttributeDeleteHandle *adh = cls; + char *data_tmp; + struct GNUNET_GNSRECORD_Data rd_new[rd_count - 1]; + struct GNUNET_RECLAIM_ATTESTATION_REFERENCE *ref; + size_t attr_len; + + if (0 == rd_count ) + { + GNUNET_log (GNUNET_ERROR_TYPE_ERROR, + "Failed to find Attestation entry for Attestation reference\n"); + cleanup_adh (adh); + GNUNET_SCHEDULER_add_now (&do_shutdown, NULL); + return; + } + if (GNUNET_GNSRECORD_TYPE_RECLAIM_ATTEST_ATTR != rd[0].record_type) + { + GNUNET_log (GNUNET_ERROR_TYPE_ERROR, + "Intended Reference location is not an attestation\n"); + cleanup_adh (adh); + GNUNET_SCHEDULER_add_now (&do_shutdown, NULL); + return; + } + rd_new[0] = rd[0]; + int i; + int j = 1; + for (i = 1; i<rd_count; i++) + { + data_tmp = GNUNET_malloc (rd[i].data_size); + GNUNET_memcpy (data_tmp, rd[i].data, rd[i].data_size); + attr_len = htons (rd[i].data_size); + ref = GNUNET_RECLAIM_ATTESTATION_REF_deserialize (data_tmp, attr_len); + if (NULL == ref ) + { + GNUNET_log (GNUNET_ERROR_TYPE_ERROR, + "Unable to parse attestation reference from %s\n", + data_tmp); + rd_new[j] = rd[i]; + j += 1; + continue; + } + if ((strcmp (adh->reference->name,ref->name) == 0)&& + (strcmp (adh->reference->reference_value,ref->reference_value)==0) ) + { + GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, + "Found reference to delete.\n"); + } + else + { + rd_new[j] = rd[i]; + j += 1; + } + GNUNET_free (data_tmp); + } + adh->ns_qe = GNUNET_NAMESTORE_records_store (nsh, + &adh->identity, + label, + j, + rd_new, + &reference_delete_cont, + adh); +} + +/** + * Check an attestation reference delete message + * + * @param cls unused + * @param sam the message to check + */ +static int +check_reference_delete_message (void *cls, + const struct AttributeDeleteMessage *dam) +{ + uint16_t size; + + size = ntohs (dam->header.size); + if (size <= sizeof(struct AttributeDeleteMessage)) + { + GNUNET_break (0); + return GNUNET_SYSERR; + } + return GNUNET_OK; +} + +/** + * Handle reference deletion + * + * @param cls our client + * @param dam deletion message + */ +static void +handle_reference_delete_message (void *cls, + const struct AttributeDeleteMessage *dam) +{ + struct AttributeDeleteHandle *adh; + struct IdpClient *idp = cls; + size_t data_len; + + GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Received REFERENCE_DELETE message\n"); + data_len = ntohs (dam->attr_len); + adh = GNUNET_new (struct AttributeDeleteHandle); + adh->reference = GNUNET_RECLAIM_ATTESTATION_REF_deserialize ((char *) &dam[1], + data_len); + adh->attest = NULL; + adh->claim = NULL; + + adh->r_id = ntohl (dam->id); + adh->identity = dam->identity; + adh->label + = GNUNET_STRINGS_data_to_string_alloc (&adh->reference->id, + sizeof(uint64_t)); + GNUNET_SERVICE_client_continue (idp->client); + adh->client = idp; + GNUNET_CONTAINER_DLL_insert (idp->delete_op_head, idp->delete_op_tail, adh); + adh->ns_qe = GNUNET_NAMESTORE_records_lookup (nsh, + &adh->identity, + adh->label, + &ref_del_error, + adh, + &ref_del_cb, + adh); +} + + /************************************************* * Attrubute iteration @@ -1372,7 +2137,7 @@ attr_iter_error (void *cls) /** - * Got record. Return if it is an attribute. + * Got record. Return if it is an attribute or attestation/reference. * * @param cls our attribute iterator * @param zone zone we are iterating @@ -1388,35 +2153,103 @@ attr_iter_cb (void *cls, const struct GNUNET_GNSRECORD_Data *rd) { struct AttributeIterator *ai = cls; - struct AttributeResultMessage *arm; struct GNUNET_MQ_Envelope *env; char *data_tmp; - if (rd_count != 1) + if (rd_count == 0) { GNUNET_NAMESTORE_zone_iterator_next (ai->ns_it, 1); return; } + if (rd_count > 1) + { + if (GNUNET_GNSRECORD_TYPE_RECLAIM_ATTR_REF == rd[0].record_type) + { + GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, + "Found Ticket. Ignoring.\n"); + GNUNET_NAMESTORE_zone_iterator_next (ai->ns_it, 1); + return; + } + else if (GNUNET_GNSRECORD_TYPE_RECLAIM_ATTEST_ATTR != rd[0].record_type) + { + GNUNET_log (GNUNET_ERROR_TYPE_ERROR, + "Non-Attestation record with multiple entries found: %u\n", + rd[0].record_type); + GNUNET_NAMESTORE_zone_iterator_next (ai->ns_it, 1); + return; + } + } - if (GNUNET_GNSRECORD_TYPE_RECLAIM_ATTR != rd->record_type) + for (int i = 0; i<rd_count; i++) { - GNUNET_NAMESTORE_zone_iterator_next (ai->ns_it, 1); - return; + if ((GNUNET_GNSRECORD_TYPE_RECLAIM_ATTR != rd[i].record_type) && + (GNUNET_GNSRECORD_TYPE_RECLAIM_ATTEST_ATTR != rd[i].record_type) && + (GNUNET_GNSRECORD_TYPE_RECLAIM_REFERENCE != rd[i].record_type)) + { + GNUNET_NAMESTORE_zone_iterator_next (ai->ns_it, 1); + return; + } + + if (GNUNET_GNSRECORD_TYPE_RECLAIM_ATTR == rd[i].record_type ) + { + struct AttributeResultMessage *arm; + GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Found attribute under: %s\n", + label); + GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, + "Sending ATTRIBUTE_RESULT message\n"); + env = GNUNET_MQ_msg_extra (arm, + rd[i].data_size, + GNUNET_MESSAGE_TYPE_RECLAIM_ATTRIBUTE_RESULT); + arm->id = htonl (ai->request_id); + arm->attr_len = htons (rd[i].data_size); + GNUNET_CRYPTO_ecdsa_key_get_public (zone, &arm->identity); + data_tmp = (char *) &arm[1]; + GNUNET_memcpy (data_tmp, rd[i].data, rd[i].data_size); + GNUNET_MQ_send (ai->client->mq, env); + } + else + { + if (GNUNET_GNSRECORD_TYPE_RECLAIM_ATTEST_ATTR == rd[i].record_type ) + { + struct AttributeResultMessage *arm; + GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Found attestation under: %s\n", + label); + GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, + "Sending ATTESTATION_RESULT message\n"); + env = GNUNET_MQ_msg_extra (arm, + rd[i].data_size, + GNUNET_MESSAGE_TYPE_RECLAIM_ATTESTATION_RESULT); + arm->id = htonl (ai->request_id); + arm->attr_len = htons (rd[i].data_size); + GNUNET_CRYPTO_ecdsa_key_get_public (zone, &arm->identity); + data_tmp = (char *) &arm[1]; + GNUNET_memcpy (data_tmp, rd[i].data, rd[i].data_size); + GNUNET_MQ_send (ai->client->mq, env); + } + else + { + struct ReferenceResultMessage *rrm; + GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Found reference under: %s\n", + label); + GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, + "Sending REFERENCE_RESULT message\n"); + env = GNUNET_MQ_msg_extra (rrm, + rd[i].data_size + rd[0].data_size, + GNUNET_MESSAGE_TYPE_RECLAIM_REFERENCE_RESULT); + rrm->id = htonl (ai->request_id); + rrm->attest_len = htons (rd[0].data_size); + rrm->ref_len = htons (rd[i].data_size); + GNUNET_CRYPTO_ecdsa_key_get_public (zone, &rrm->identity); + data_tmp = (char *) &rrm[1]; + GNUNET_memcpy (data_tmp, rd[0].data, rd[0].data_size); + data_tmp += rd[0].data_size; + GNUNET_memcpy (data_tmp, rd[i].data, rd[i].data_size); + GNUNET_MQ_send (ai->client->mq, env); + } + } } - GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Found attribute under: %s\n", label); - GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Sending ATTRIBUTE_RESULT message\n"); - env = GNUNET_MQ_msg_extra (arm, - rd->data_size, - GNUNET_MESSAGE_TYPE_RECLAIM_ATTRIBUTE_RESULT); - arm->id = htonl (ai->request_id); - arm->attr_len = htons (rd->data_size); - GNUNET_CRYPTO_ecdsa_key_get_public (zone, &arm->identity); - data_tmp = (char *) &arm[1]; - GNUNET_memcpy (data_tmp, rd->data, rd->data_size); - GNUNET_MQ_send (ai->client->mq, env); } - /** * Iterate over zone to get attributes * @@ -1742,10 +2575,26 @@ GNUNET_SERVICE_MAIN ( GNUNET_MESSAGE_TYPE_RECLAIM_ATTRIBUTE_STORE, struct AttributeStoreMessage, NULL), + GNUNET_MQ_hd_var_size (attestation_store_message, + GNUNET_MESSAGE_TYPE_RECLAIM_ATTESTATION_STORE, + struct AttributeStoreMessage, + NULL), GNUNET_MQ_hd_var_size (attribute_delete_message, GNUNET_MESSAGE_TYPE_RECLAIM_ATTRIBUTE_DELETE, struct AttributeDeleteMessage, NULL), + GNUNET_MQ_hd_var_size (attestation_delete_message, + GNUNET_MESSAGE_TYPE_RECLAIM_ATTESTATION_DELETE, + struct AttributeDeleteMessage, + NULL), + GNUNET_MQ_hd_var_size (reference_store_message, + GNUNET_MESSAGE_TYPE_RECLAIM_REFERENCE_STORE, + struct AttributeStoreMessage, + NULL), + GNUNET_MQ_hd_var_size (reference_delete_message, + GNUNET_MESSAGE_TYPE_RECLAIM_REFERENCE_DELETE, + struct AttributeDeleteMessage, + NULL), GNUNET_MQ_hd_fixed_size ( iteration_start, GNUNET_MESSAGE_TYPE_RECLAIM_ATTRIBUTE_ITERATION_START, diff --git a/src/reclaim/gnunet-service-reclaim_tickets.c b/src/reclaim/gnunet-service-reclaim_tickets.c index 4d1a26333..b022225b8 100644 --- a/src/reclaim/gnunet-service-reclaim_tickets.c +++ b/src/reclaim/gnunet-service-reclaim_tickets.c @@ -667,8 +667,7 @@ rvk_move_attr_cb (void *cls, const struct GNUNET_GNSRECORD_Data *rd) { struct RECLAIM_TICKETS_RevokeHandle *rvk = cls; - struct GNUNET_RECLAIM_ATTRIBUTE_Claim *claim; - struct GNUNET_GNSRECORD_Data new_rd; + struct GNUNET_GNSRECORD_Data new_rd[rd_count]; struct RevokedAttributeEntry *le; char *new_label; char *attr_data; @@ -677,7 +676,7 @@ rvk_move_attr_cb (void *cls, if (0 == rd_count) { GNUNET_log (GNUNET_ERROR_TYPE_WARNING, - "The attribute %s no longer exists!\n", + "The claim %s no longer exists!\n", label); le = rvk->move_attr; rvk->move_attr = le->next; @@ -686,32 +685,82 @@ rvk_move_attr_cb (void *cls, GNUNET_SCHEDULER_add_now (&move_attrs_cont, rvk); return; } - /** find a new place for this attribute **/ - rvk->move_attr->new_id = - GNUNET_CRYPTO_random_u64 (GNUNET_CRYPTO_QUALITY_STRONG, UINT64_MAX); - new_rd = *rd; - claim = GNUNET_RECLAIM_ATTRIBUTE_deserialize (rd->data, rd->data_size); - GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, - "Attribute to update: Name=%s, ID=%" PRIu64 "\n", - claim->name, - claim->id); - claim->id = rvk->move_attr->new_id; - new_rd.data_size = GNUNET_RECLAIM_ATTRIBUTE_serialize_get_size (claim); - attr_data = GNUNET_malloc (rd->data_size); - new_rd.data_size = GNUNET_RECLAIM_ATTRIBUTE_serialize (claim, attr_data); - new_rd.data = attr_data; - new_label = GNUNET_STRINGS_data_to_string_alloc (&rvk->move_attr->new_id, - sizeof(uint64_t)); - GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Adding attribute %s\n", new_label); + rvk->move_attr->new_id =GNUNET_CRYPTO_random_u64 (GNUNET_CRYPTO_QUALITY_STRONG, UINT64_MAX); + new_label=NULL; + attr_data=NULL; + //new_rd = *rd; + for (int i = 0; i < rd_count; i++) + { + if (GNUNET_GNSRECORD_TYPE_RECLAIM_ATTR == rd[i].record_type) + { + /** find a new place for this attribute **/ + struct GNUNET_RECLAIM_ATTRIBUTE_Claim *claim; + claim = GNUNET_RECLAIM_ATTRIBUTE_deserialize (rd[i].data, rd[i].data_size); + GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, + "Attribute to update: Name=%s, ID=%" PRIu64 "\n", + claim->name, + claim->id); + claim->id = rvk->move_attr->new_id; + new_rd[i].data_size = GNUNET_RECLAIM_ATTRIBUTE_serialize_get_size (claim); + attr_data = GNUNET_malloc (rd[i].data_size); + new_rd[i].data_size = GNUNET_RECLAIM_ATTRIBUTE_serialize (claim, attr_data); + new_rd[i].data = attr_data; + new_rd[i].record_type = rd[i].record_type; + new_rd[i].flags = rd[i].flags; + new_rd[i].expiration_time = rd[i].expiration_time; + new_label = GNUNET_STRINGS_data_to_string_alloc (&rvk->move_attr->new_id, + sizeof(uint64_t)); + GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Adding attribute %s\n", new_label); + GNUNET_free (claim); + } else if (GNUNET_GNSRECORD_TYPE_RECLAIM_ATTEST_ATTR == rd[i].record_type) + { + struct GNUNET_RECLAIM_ATTESTATION_Claim *attest; + attest=GNUNET_RECLAIM_ATTESTATION_deserialize(rd[i].data, rd[i].data_size); + GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, + "Attestation to update: Name=%s, ID=%" PRIu64 "\n", + attest->name, + attest->id); + attest->id = rvk->move_attr->new_id; + new_rd[i].data_size = GNUNET_RECLAIM_ATTESTATION_serialize_get_size (attest); + attr_data = GNUNET_malloc (rd[i].data_size); + new_rd[i].data_size = GNUNET_RECLAIM_ATTESTATION_serialize (attest, attr_data); + new_rd[i].data = attr_data; + new_rd[i].record_type = rd[i].record_type; + new_rd[i].flags = rd[i].flags; + new_rd[i].expiration_time = rd[i].expiration_time; + new_label = GNUNET_STRINGS_data_to_string_alloc (&rvk->move_attr->new_id, sizeof(uint64_t)); + GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Adding attestation %s\n", new_label); + GNUNET_free (attest); + } else if (GNUNET_GNSRECORD_TYPE_RECLAIM_REFERENCE == rd[i].record_type) + { + struct GNUNET_RECLAIM_ATTESTATION_REFERENCE *reference; + reference=GNUNET_RECLAIM_ATTESTATION_REF_deserialize(rd[i].data, rd[i].data_size); + GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, + "Reference to update: Name=%s, ID=%" PRIu64 "\n", + reference->name, + reference->id); + reference->id = rvk->move_attr->new_id; + reference->id_attest = rvk->move_attr->new_id; + new_rd[i].data_size = GNUNET_RECLAIM_ATTESTATION_REF_serialize_get_size (reference); + attr_data = GNUNET_malloc (rd[i].data_size); + new_rd[i].data_size = GNUNET_RECLAIM_ATTESTATION_REF_serialize (reference, attr_data); + new_rd[i].data = attr_data; + new_label = GNUNET_STRINGS_data_to_string_alloc (&rvk->move_attr->new_id, sizeof(uint64_t)); + new_rd[i].record_type = rd[i].record_type; + new_rd[i].flags = rd[i].flags; + new_rd[i].expiration_time = rd[i].expiration_time; + GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Adding reference %s\n", new_label); + GNUNET_free (reference); + } + } rvk->ns_qe = GNUNET_NAMESTORE_records_store (nsh, - &rvk->identity, - new_label, - 1, - &new_rd, - &move_attr_finished, - rvk); + &rvk->identity, + new_label, + rd_count, + new_rd, + &move_attr_finished, + rvk); GNUNET_free (new_label); - GNUNET_free (claim); GNUNET_free (attr_data); } @@ -745,7 +794,7 @@ move_attrs (struct RECLAIM_TICKETS_RevokeHandle *rvk) } label = GNUNET_STRINGS_data_to_string_alloc (&rvk->move_attr->old_id, sizeof(uint64_t)); - GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Moving attribute %s\n", label); + GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Moving claim %s\n", label); rvk->ns_qe = GNUNET_NAMESTORE_records_lookup (nsh, &rvk->identity, @@ -982,21 +1031,70 @@ process_parallel_lookup_result (void *cls, GNUNET_free (parallel_lookup); - if (1 != rd_count) - GNUNET_break (0); // FIXME: We should never find this. - if (rd->record_type == GNUNET_GNSRECORD_TYPE_RECLAIM_ATTR) + if (0 == rd_count) + GNUNET_break (0); + // REMARK: It is possible now to find rd_count > 1 + for (int i = 0; i < rd_count; i++) { - attr_le = GNUNET_new (struct GNUNET_RECLAIM_ATTRIBUTE_ClaimListEntry); - attr_le->claim = - GNUNET_RECLAIM_ATTRIBUTE_deserialize (rd->data, rd->data_size); - GNUNET_CONTAINER_DLL_insert (cth->attrs->list_head, - cth->attrs->list_tail, - attr_le); - } + if (GNUNET_GNSRECORD_TYPE_RECLAIM_ATTR == rd[i].record_type) + { + attr_le = GNUNET_new (struct GNUNET_RECLAIM_ATTRIBUTE_ClaimListEntry); + attr_le->claim = + GNUNET_RECLAIM_ATTRIBUTE_deserialize (rd[i].data, rd[i].data_size); + GNUNET_CONTAINER_DLL_insert (cth->attrs->list_head, + cth->attrs->list_tail, + attr_le); + attr_le->reference = NULL; + attr_le->attest = NULL; + } + else if (GNUNET_GNSRECORD_TYPE_RECLAIM_ATTEST_ATTR == rd[i].record_type) + { + /**Ignore all plain attestations + *attr_le = GNUNET_new (struct GNUNET_RECLAIM_ATTRIBUTE_ClaimListEntry); + *attr_le->attest = + * GNUNET_RECLAIM_ATTESTATION_deserialize (rd[i].data, rd[i].data_size); + *GNUNET_CONTAINER_DLL_insert (cth->attrs->list_head, + * cth->attrs->list_tail, + * attr_le); + */ + continue; + } + else if (GNUNET_GNSRECORD_TYPE_RECLAIM_REFERENCE == rd[i].record_type) + { + struct GNUNET_RECLAIM_ATTRIBUTE_ClaimListEntry *attr_le2; + attr_le = GNUNET_new (struct GNUNET_RECLAIM_ATTRIBUTE_ClaimListEntry); + attr_le2 = GNUNET_new (struct GNUNET_RECLAIM_ATTRIBUTE_ClaimListEntry); + if (GNUNET_GNSRECORD_TYPE_RECLAIM_ATTEST_ATTR == rd[0].record_type) + { + attr_le->attest = GNUNET_RECLAIM_ATTESTATION_deserialize (rd[0].data, + rd[0]. + data_size); + attr_le2->reference = + GNUNET_RECLAIM_ATTESTATION_REF_deserialize (rd[i].data, + rd[i].data_size); + attr_le->claim = NULL; + attr_le->reference = NULL; + attr_le2->claim = NULL; + attr_le2->attest = NULL; + GNUNET_CONTAINER_DLL_insert (cth->attrs->list_head, + cth->attrs->list_tail, + attr_le); + GNUNET_CONTAINER_DLL_insert (cth->attrs->list_head, + cth->attrs->list_tail, + attr_le2); + } + else + { + GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, + "Parallel Lookup of Reference without Attestation"); + continue; + } + + } + } if (NULL != cth->parallel_lookups_head) return; // Wait for more - /* Else we are done */ cth->cb (cth->cb_cls, &cth->ticket.identity, cth->attrs, GNUNET_OK, NULL); cleanup_cth (cth); @@ -1076,7 +1174,7 @@ lookup_authz_cb (void *cls, GNUNET_GNS_lookup (gns, lbl, &cth->ticket.identity, - GNUNET_GNSRECORD_TYPE_RECLAIM_ATTR, + GNUNET_GNSRECORD_TYPE_ANY, GNUNET_GNS_LO_DEFAULT, &process_parallel_lookup_result, parallel_lookup); @@ -1223,6 +1321,7 @@ issue_ticket (struct TicketIssueHandle *ih) char *label; size_t list_len = 1; int i; + char *attest_string; for (le = ih->attrs->list_head; NULL != le; le = le->next) list_len++; @@ -1232,8 +1331,51 @@ issue_ticket (struct TicketIssueHandle *ih) i = 0; for (le = ih->attrs->list_head; NULL != le; le = le->next) { - attrs_record[i].data = &le->claim->id; - attrs_record[i].data_size = sizeof(le->claim->id); + if (NULL != le->claim) + { + attrs_record[i].data = &le->claim->id; + attrs_record[i].data_size = sizeof(le->claim->id); + } + else if (NULL != le->attest) + { + // REMARK: Since we only store IDs, the references are irrelevant + int j = 0; + GNUNET_asprintf (&attest_string,"%d",le->attest->id); + while (j<i) + { + if (0 == strcmp (attest_string,GNUNET_STRINGS_data_to_string_alloc ( + attrs_record[j].data, attrs_record[j].data_size))) + break; + j++; + } + if (j < i) + { + list_len--; + continue; + } + attrs_record[i].data = &le->attest->id; + attrs_record[i].data_size = sizeof(le->attest->id); + } + else if (NULL != le->reference) + { + list_len--; + continue; + /* + int j = 0; + GNUNET_asprintf (&attest_string,"%d",le->attest->id); + while (j<i) + { + if (strcmp(attest_string, GNUNET_STRINGS_data_to_string_alloc ( + attrs_record[j].data, attrs_record[j].data_size))) + break; + j++; + } + if (j < i) + continue; + attrs_record[i].data = &le->reference->id; + attrs_record[i].data_size = sizeof(le->reference->id); + */ + } /** * FIXME: Should this be the attribute expiration time or ticket * refresh interval? Probably min(attrs.expiration) @@ -1344,14 +1486,34 @@ filter_tickets_cb (void *cls, for (le = tih->attrs->list_head; NULL != le; le = le->next) { // cmp attr_ref id with requested attr id - GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, - " %" PRIu64 "\n %" PRIu64 "\n", - *((uint64_t *) rd[i].data), - le->claim->id); - + if (NULL !=le->claim) + { + GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, + " %" PRIu64 "\n %" PRIu64 "\n", + *((uint64_t *) rd[i].data), + le->claim->id); + if (0 == memcmp (rd[i].data, &le->claim->id, sizeof(uint64_t))) + found_attrs_cnt++; + } + else if (NULL !=le->attest) + { + GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, + " %" PRIu64 "\n %" PRIu64 "\n", + *((uint64_t *) rd[i].data), + le->attest->id); + if (0 == memcmp (rd[i].data, &le->attest->id, sizeof(uint64_t))) + found_attrs_cnt++; + } + else if (NULL != le->reference) + { + GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, + " %" PRIu64 "\n %" PRIu64 "\n", + *((uint64_t *) rd[i].data), + le->reference->id); + if (0 == memcmp (rd[i].data, &le->reference->id, sizeof(uint64_t))) + found_attrs_cnt++; + } - if (0 == memcmp (rd[i].data, &le->claim->id, sizeof(uint64_t))) - found_attrs_cnt++; } } diff --git a/src/reclaim/json_reclaim.c b/src/reclaim/json_reclaim.c index e029fdfb6..a464a9088 100644 --- a/src/reclaim/json_reclaim.c +++ b/src/reclaim/json_reclaim.c @@ -48,6 +48,7 @@ parse_attr (void *cls, json_t *root, struct GNUNET_JSON_Specification *spec) const char *val_str = NULL; const char *type_str = NULL; const char *id_str = NULL; + const char *flag_str = NULL; char *data; int unpack_state; uint32_t type; @@ -63,7 +64,7 @@ parse_attr (void *cls, json_t *root, struct GNUNET_JSON_Specification *spec) } // interpret single attribute unpack_state = json_unpack (root, - "{s:s, s?s, s:s, s:s!}", + "{s:s, s?s, s:s, s:s, s?s!}", "name", &name_str, "id", @@ -71,7 +72,9 @@ parse_attr (void *cls, json_t *root, struct GNUNET_JSON_Specification *spec) "type", &type_str, "value", - &val_str); + &val_str, + "flag", + &flag_str); if ((0 != unpack_state) || (NULL == name_str) || (NULL == val_str) || (NULL == type_str)) { @@ -264,3 +267,217 @@ GNUNET_RECLAIM_JSON_spec_ticket (struct GNUNET_RECLAIM_Ticket **ticket) *ticket = NULL; return ret; } + +/** + * Parse given JSON object to an attestation claim + * + * @param cls closure, NULL + * @param root the json object representing data + * @param spec where to write the data + * @return #GNUNET_OK upon successful parsing; #GNUNET_SYSERR upon error + */ +static int +parse_attest (void *cls, json_t *root, struct GNUNET_JSON_Specification *spec) +{ + struct GNUNET_RECLAIM_ATTESTATION_Claim *attr; + const char *name_str = NULL; + const char *val_str = NULL; + const char *type_str = NULL; + const char *id_str = NULL; + char *data; + int unpack_state; + uint32_t type; + size_t data_size; + + GNUNET_assert (NULL != root); + + if (! json_is_object (root)) + { + GNUNET_log (GNUNET_ERROR_TYPE_ERROR, + "Error json is not array nor object!\n"); + return GNUNET_SYSERR; + } + // interpret single attribute + unpack_state = json_unpack (root, + "{s:s, s?s, s:s, s:s!}", + "name", + &name_str, + "id", + &id_str, + "type", + &type_str, + "value", + &val_str); + if ((0 != unpack_state) || (NULL == name_str) || (NULL == val_str) || + (NULL == type_str)) + { + GNUNET_log (GNUNET_ERROR_TYPE_ERROR, + "Error json object has a wrong format!\n"); + return GNUNET_SYSERR; + } + type = GNUNET_RECLAIM_ATTESTATION_typename_to_number (type_str); + if (GNUNET_SYSERR == + (GNUNET_RECLAIM_ATTESTATION_string_to_value (type, + val_str, + (void **) &data, + &data_size))) + { + GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Attestation value invalid!\n"); + return GNUNET_SYSERR; + } + attr = GNUNET_RECLAIM_ATTESTATION_claim_new (name_str, type, data, data_size); + if ((NULL == id_str) || (0 == strlen (id_str))) + attr->id = 0; + else + GNUNET_STRINGS_string_to_data (id_str, + strlen (id_str), + &attr->id, + sizeof(uint64_t)); + + *(struct GNUNET_RECLAIM_ATTESTATION_Claim **) spec->ptr = attr; + return GNUNET_OK; +} + +/** + * Cleanup data left from parsing RSA public key. + * + * @param cls closure, NULL + * @param[out] spec where to free the data + */ +static void +clean_attest (void *cls, struct GNUNET_JSON_Specification *spec) +{ + struct GNUNET_RECLAIM_ATTESTATION_Claim **attr; + + attr = (struct GNUNET_RECLAIM_ATTESTATION_Claim **) spec->ptr; + if (NULL != *attr) + { + GNUNET_free (*attr); + *attr = NULL; + } +} +/** + * JSON Specification for Reclaim attestation claims. + * + * @param ticket struct of GNUNET_RECLAIM_ATTESTATION_Claim to fill + * @return JSON Specification + */ +struct GNUNET_JSON_Specification +GNUNET_RECLAIM_JSON_spec_claim_attest (struct + GNUNET_RECLAIM_ATTESTATION_Claim **attr) +{ + struct GNUNET_JSON_Specification ret = { .parser = &parse_attest, + .cleaner = &clean_attest, + .cls = NULL, + .field = NULL, + .ptr = attr, + .ptr_size = 0, + .size_ptr = NULL }; + + *attr = NULL; + return ret; +} + +/** + * Parse given JSON object to an attestation claim + * + * @param cls closure, NULL + * @param root the json object representing data + * @param spec where to write the data + * @return #GNUNET_OK upon successful parsing; #GNUNET_SYSERR upon error + */ +static int +parse_attest_ref (void *cls, json_t *root, struct + GNUNET_JSON_Specification *spec) +{ + struct GNUNET_RECLAIM_ATTESTATION_REFERENCE *attr; + const char *name_str = NULL; + const char *ref_val_str = NULL; + const char *ref_id_str = NULL; + const char *id_str = NULL; + int unpack_state; + + GNUNET_assert (NULL != root); + + if (! json_is_object (root)) + { + GNUNET_log (GNUNET_ERROR_TYPE_ERROR, + "Error json is not array nor object!\n"); + return GNUNET_SYSERR; + } + // interpret single reference + unpack_state = json_unpack (root, + "{s:s, s?s, s:s, s:s!}", + "name", + &name_str, + "id", + &id_str, + "ref_id", + &ref_id_str, + "ref_value", + &ref_val_str); + if ((0 != unpack_state) || (NULL == name_str) || (NULL == ref_val_str) || + (NULL == ref_id_str)) + { + GNUNET_log (GNUNET_ERROR_TYPE_ERROR, + "Error json object has a wrong format!\n"); + return GNUNET_SYSERR; + } + + attr = GNUNET_RECLAIM_ATTESTATION_reference_new (name_str, ref_val_str); + + attr->id = 0; + + if ((NULL == ref_id_str) || (0 == strlen (ref_id_str))) + attr->id_attest = 0; + else + GNUNET_STRINGS_string_to_data (ref_id_str, + strlen (ref_id_str), + &attr->id_attest, + sizeof(uint64_t)); + + *(struct GNUNET_RECLAIM_ATTESTATION_REFERENCE **) spec->ptr = attr; + return GNUNET_OK; +} + +/** + * Cleanup data left from parsing RSA public key. + * + * @param cls closure, NULL + * @param[out] spec where to free the data + */ +static void +clean_attest_ref (void *cls, struct GNUNET_JSON_Specification *spec) +{ + struct GNUNET_RECLAIM_ATTESTATION_REFERENCE **attr; + + attr = (struct GNUNET_RECLAIM_ATTESTATION_REFERENCE **) spec->ptr; + if (NULL != *attr) + { + GNUNET_free (*attr); + *attr = NULL; + } +} + +/** + * JSON Specification for Reclaim attestation references. + * + * @param ticket struct of GNUNET_RECLAIM_ATTESTATION_REFERENCE to fill + * @return JSON Specification + */ +struct GNUNET_JSON_Specification +GNUNET_RECLAIM_JSON_spec_claim_attest_ref (struct + GNUNET_RECLAIM_ATTESTATION_REFERENCE + **attr) +{ + struct GNUNET_JSON_Specification ret = { .parser = &parse_attest_ref, + .cleaner = &clean_attest_ref, + .cls = NULL, + .field = NULL, + .ptr = attr, + .ptr_size = 0, + .size_ptr = NULL }; + + *attr = NULL; + return ret; +}
\ No newline at end of file diff --git a/src/reclaim/json_reclaim.h b/src/reclaim/json_reclaim.h index 3fd26167f..9e6479e5e 100644 --- a/src/reclaim/json_reclaim.h +++ b/src/reclaim/json_reclaim.h @@ -46,3 +46,22 @@ GNUNET_RECLAIM_JSON_spec_claim (struct GNUNET_RECLAIM_ATTRIBUTE_Claim **attr); */ struct GNUNET_JSON_Specification GNUNET_RECLAIM_JSON_spec_ticket (struct GNUNET_RECLAIM_Ticket **ticket); + +/** + * JSON Specification for Reclaim attestation claims. + * + * @param ticket struct of GNUNET_RECLAIM_ATTESTATION_Claim to fill + * @return JSON Specification + */ +struct GNUNET_JSON_Specification +GNUNET_RECLAIM_JSON_spec_claim_attest (struct + GNUNET_RECLAIM_ATTESTATION_Claim **attr); + + /** + * JSON Specification for Reclaim attestation references. + * + * @param ticket struct of GNUNET_RECLAIM_ATTESTATION_REFERENCE to fill + * @return JSON Specification + */ + struct GNUNET_JSON_Specification + GNUNET_RECLAIM_JSON_spec_claim_attest_ref(struct GNUNET_RECLAIM_ATTESTATION_REFERENCE **attr); diff --git a/src/reclaim/oidc_helper.c b/src/reclaim/oidc_helper.c index 1c3d65f35..2ce462854 100644 --- a/src/reclaim/oidc_helper.c +++ b/src/reclaim/oidc_helper.c @@ -118,7 +118,7 @@ fix_base64 (char *str) char * OIDC_id_token_new (const struct GNUNET_CRYPTO_EcdsaPublicKey *aud_key, const struct GNUNET_CRYPTO_EcdsaPublicKey *sub_key, - const struct GNUNET_RECLAIM_ATTRIBUTE_ClaimList *attrs, + struct GNUNET_RECLAIM_ATTRIBUTE_ClaimList *attrs, const struct GNUNET_TIME_Relative *expiration_time, const char *nonce, const char *secret_key) @@ -131,13 +131,22 @@ OIDC_id_token_new (const struct GNUNET_CRYPTO_EcdsaPublicKey *aud_key, char *subject; char *header; char *body_str; + char *aggr_names_str; + char *aggr_sources_str; + char *aggr_sources_jwt_str; + char *source_name; char *result; char *header_base64; char *body_base64; char *signature_target; char *signature_base64; char *attr_val_str; + char *attest_val_str; json_t *body; + json_t *aggr_names; + json_t *aggr_sources; + json_t *aggr_sources_jwt; + uint64_t attest_arr[GNUNET_RECLAIM_ATTRIBUTE_list_count_attest (attrs)]; // iat REQUIRED time now time_now = GNUNET_TIME_absolute_get (); @@ -156,6 +165,8 @@ OIDC_id_token_new (const struct GNUNET_CRYPTO_EcdsaPublicKey *aud_key, GNUNET_CRYPTO_EcdsaPublicKey)); header = create_jwt_header (); body = json_object (); + aggr_names = json_object (); + aggr_sources = json_object (); // iss REQUIRED case sensitive server uri with https // The issuer is the local reclaim instance (e.g. @@ -180,18 +191,111 @@ OIDC_id_token_new (const struct GNUNET_CRYPTO_EcdsaPublicKey *aud_key, // nonce if (NULL != nonce) json_object_set_new (body, "nonce", json_string (nonce)); - + int i = 0; + attest_val_str = NULL; + aggr_names_str = NULL; + aggr_sources_str = NULL; + aggr_sources_jwt_str = NULL; + source_name = NULL; for (le = attrs->list_head; NULL != le; le = le->next) { - attr_val_str = - GNUNET_RECLAIM_ATTRIBUTE_value_to_string (le->claim->type, - le->claim->data, - le->claim->data_size); - json_object_set_new (body, le->claim->name, json_string (attr_val_str)); - GNUNET_free (attr_val_str); + + if (le->claim != NULL) + { + + attr_val_str = + GNUNET_RECLAIM_ATTRIBUTE_value_to_string (le->claim->type, + le->claim->data, + le->claim->data_size); + json_object_set_new (body, le->claim->name, json_string (attr_val_str)); + GNUNET_free (attr_val_str); + } + else if (NULL != le->reference) + { + // Check if attest is there + int j = 0; + while (j<i) + { + if (attest_arr[j] == le->reference->id_attest) + break; + j++; + } + if (j==i) + { + // Attest not yet existent. Append to the end of the list + GNUNET_CONTAINER_DLL_remove (attrs->list_head, attrs->list_tail, le); + GNUNET_CONTAINER_DLL_insert_tail (attrs->list_head, attrs->list_tail, + le); + continue; + } + else + { + // Attestation is existing, hence take the respective source str + GNUNET_asprintf (&source_name, + "src%d", + j); + json_object_set_new (aggr_names, le->reference->name, json_string ( + source_name)); + } + + } + else if (NULL != le->attest) + { + // We assume that at max 99 different attestations + int j = 0; + while (j<i) + { + if (attest_arr[j] == le->attest->id) + break; + j++; + } + if (j==i) + { + // New Attestation + attest_arr[i] = le->attest->id; + GNUNET_asprintf (&source_name, + "src%d", + i); + aggr_sources_jwt = json_object (); + attest_val_str = GNUNET_RECLAIM_ATTESTATION_value_to_string ( + le->attest->type, le->attest->data, le->attest->data_size); + json_object_set_new (aggr_sources_jwt, "JWT",json_string ( + attest_val_str) ); + aggr_sources_jwt_str = json_dumps (aggr_sources_jwt, JSON_INDENT (0) + | JSON_COMPACT); + json_object_set_new (aggr_sources, source_name,json_string ( + aggr_sources_jwt_str)); + i++; + } + else + { + // Attestation already existent. Ignore + continue; + } + + } + } + if (NULL != attest_val_str) + GNUNET_free (attest_val_str); + if (NULL != source_name) + GNUNET_free (source_name); + if (0!=i) + { + aggr_names_str = json_dumps (aggr_names, JSON_INDENT (0) | JSON_COMPACT); + aggr_sources_str = json_dumps (aggr_sources, JSON_INDENT (0) + | JSON_COMPACT); + json_object_set_new (body, "_claim_names", json_string (aggr_names_str)); + json_object_set_new (body, "_claim_sources", json_string ( + aggr_sources_str)); } + + json_decref (aggr_names); + json_decref (aggr_sources); + json_decref (aggr_sources_jwt); + body_str = json_dumps (body, JSON_INDENT (0) | JSON_COMPACT); json_decref (body); + GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,"ID-Token: %s\n", body_str); GNUNET_STRINGS_base64_encode (header, strlen (header), &header_base64); fix_base64 (header_base64); @@ -226,6 +330,12 @@ OIDC_id_token_new (const struct GNUNET_CRYPTO_EcdsaPublicKey *aud_key, GNUNET_free (signature_target); GNUNET_free (header); GNUNET_free (body_str); + if (NULL != aggr_sources_str) + GNUNET_free (aggr_sources_str); + if (NULL != aggr_names_str) + GNUNET_free (aggr_names_str); + if (NULL != aggr_sources_jwt_str) + GNUNET_free (aggr_sources_jwt_str); GNUNET_free (signature_base64); GNUNET_free (body_base64); GNUNET_free (header_base64); diff --git a/src/reclaim/oidc_helper.h b/src/reclaim/oidc_helper.h index 1774618e8..a7072755b 100644 --- a/src/reclaim/oidc_helper.h +++ b/src/reclaim/oidc_helper.h @@ -51,7 +51,7 @@ char* OIDC_id_token_new (const struct GNUNET_CRYPTO_EcdsaPublicKey *aud_key, const struct GNUNET_CRYPTO_EcdsaPublicKey *sub_key, - const struct GNUNET_RECLAIM_ATTRIBUTE_ClaimList *attrs, + struct GNUNET_RECLAIM_ATTRIBUTE_ClaimList *attrs, const struct GNUNET_TIME_Relative *expiration_time, const char *nonce, const char *secret_key); diff --git a/src/reclaim/plugin_gnsrecord_reclaim.c b/src/reclaim/plugin_gnsrecord_reclaim.c index d530ef01d..f7145a272 100644 --- a/src/reclaim/plugin_gnsrecord_reclaim.c +++ b/src/reclaim/plugin_gnsrecord_reclaim.c @@ -54,6 +54,8 @@ value_to_string (void *cls, uint32_t type, const void *data, size_t data_size) case GNUNET_GNSRECORD_TYPE_RECLAIM_ATTR_REF: case GNUNET_GNSRECORD_TYPE_RECLAIM_TICKET: case GNUNET_GNSRECORD_TYPE_RECLAIM_MASTER: + case GNUNET_GNSRECORD_TYPE_RECLAIM_ATTEST_ATTR: + case GNUNET_GNSRECORD_TYPE_RECLAIM_REFERENCE: return GNUNET_STRINGS_data_to_string_alloc (data, data_size); default: @@ -93,6 +95,8 @@ string_to_value (void *cls, uint32_t type, const char *s, void **data, case GNUNET_GNSRECORD_TYPE_RECLAIM_ATTR_REF: case GNUNET_GNSRECORD_TYPE_RECLAIM_MASTER: case GNUNET_GNSRECORD_TYPE_RECLAIM_TICKET: + case GNUNET_GNSRECORD_TYPE_RECLAIM_ATTEST_ATTR: + case GNUNET_GNSRECORD_TYPE_RECLAIM_REFERENCE: return GNUNET_STRINGS_string_to_data (s, strlen (s), *data, *data_size); default: @@ -112,10 +116,12 @@ static struct } name_map[] = { { "RECLAIM_ATTR", GNUNET_GNSRECORD_TYPE_RECLAIM_ATTR }, { "RECLAIM_ATTR_REF", GNUNET_GNSRECORD_TYPE_RECLAIM_ATTR_REF }, + { "RECLAIM_ATTEST", GNUNET_GNSRECORD_TYPE_RECLAIM_ATTEST_ATTR }, { "RECLAIM_MASTER", GNUNET_GNSRECORD_TYPE_RECLAIM_MASTER }, { "RECLAIM_OIDC_CLIENT", GNUNET_GNSRECORD_TYPE_RECLAIM_OIDC_CLIENT }, { "RECLAIM_OIDC_REDIRECT", GNUNET_GNSRECORD_TYPE_RECLAIM_OIDC_REDIRECT }, { "RECLAIM_TICKET", GNUNET_GNSRECORD_TYPE_RECLAIM_TICKET }, + { "RECLAIM_REFERENCE", GNUNET_GNSRECORD_TYPE_RECLAIM_REFERENCE }, { NULL, UINT32_MAX } }; diff --git a/src/reclaim/plugin_rest_openid_connect.c b/src/reclaim/plugin_rest_openid_connect.c index 92a1de621..741094f21 100644 --- a/src/reclaim/plugin_rest_openid_connect.c +++ b/src/reclaim/plugin_rest_openid_connect.c @@ -120,6 +120,11 @@ #define OIDC_NONCE_KEY "nonce" /** + * OIDC claims key + */ +#define OIDC_CLAIMS_KEY "claims" + +/** * OIDC PKCE code challenge */ #define OIDC_CODE_CHALLENGE_KEY "code_challenge" @@ -291,6 +296,11 @@ struct OIDC_Variables char *nonce; /** + * The OIDC claims + */ + char *claims; + + /** * The OIDC response type */ char *response_type; @@ -560,7 +570,12 @@ cleanup_handle (struct RequestHandle *handle) { claim_tmp = claim_entry; claim_entry = claim_entry->next; - GNUNET_free (claim_tmp->claim); + if (NULL != claim_tmp->claim) + GNUNET_free (claim_tmp->claim); + if (NULL != claim_tmp->attest) + GNUNET_free (claim_tmp->attest); + if (NULL != claim_tmp->reference) + GNUNET_free (claim_tmp->reference); GNUNET_free (claim_tmp); } GNUNET_free (handle->attr_list); @@ -697,7 +712,7 @@ return_userinfo_response (void *cls) struct MHD_Response *resp; result_str = json_dumps (handle->oidc->response, 0); - + GNUNET_log (GNUNET_ERROR_TYPE_ERROR,"ID-Token: %s\n",result_str); resp = GNUNET_REST_create_response (result_str); handle->proc (handle->proc_cls, resp, MHD_HTTP_OK); GNUNET_free (result_str); @@ -838,7 +853,7 @@ login_redirect (void *cls) &login_base_url)) { GNUNET_asprintf (&new_redirect, - "%s?%s=%s&%s=%s&%s=%s&%s=%s&%s=%s&%s=%s&%s=%s", + "%s?%s=%s&%s=%s&%s=%s&%s=%s&%s=%s&%s=%s&%s=%s&%s=%s", login_base_url, OIDC_RESPONSE_TYPE_KEY, handle->oidc->response_type, @@ -854,7 +869,10 @@ login_redirect (void *cls) (NULL != handle->oidc->code_challenge) ? handle->oidc->code_challenge : "", OIDC_NONCE_KEY, - (NULL != handle->oidc->nonce) ? handle->oidc->nonce : ""); + (NULL != handle->oidc->nonce) ? handle->oidc->nonce : "", + OIDC_CLAIMS_KEY, + (NULL != handle->oidc->claims) ? handle->oidc->claims : + ""); resp = GNUNET_REST_create_response (""); MHD_add_response_header (resp, "Location", new_redirect); GNUNET_free (login_base_url); @@ -973,12 +991,14 @@ oidc_collect_finished_cb (void *cls) /** - * Collects all attributes for an ego if in scope parameter + * Collects all attributes/references for an ego if in scope parameter */ static void oidc_attr_collect (void *cls, const struct GNUNET_CRYPTO_EcdsaPublicKey *identity, - const struct GNUNET_RECLAIM_ATTRIBUTE_Claim *attr) + const struct GNUNET_RECLAIM_ATTRIBUTE_Claim *attr, + const struct GNUNET_RECLAIM_ATTESTATION_Claim *attest, + const struct GNUNET_RECLAIM_ATTESTATION_REFERENCE *reference) { struct RequestHandle *handle = cls; struct GNUNET_RECLAIM_ATTRIBUTE_ClaimListEntry *le; @@ -986,39 +1006,92 @@ oidc_attr_collect (void *cls, char *scope_variable; char delimiter[] = " "; - if ((NULL == attr->name) || (NULL == attr->data)) + if ((NULL == attr) && (NULL == reference)) { GNUNET_RECLAIM_get_attributes_next (handle->attr_it); return; } - - scope_variables = GNUNET_strdup (handle->oidc->scope); - scope_variable = strtok (scope_variables, delimiter); - while (NULL != scope_variable) - { - if (0 == strcmp (attr->name, scope_variable)) - break; - scope_variable = strtok (NULL, delimiter); - } - if (NULL == scope_variable) + if (NULL != reference) { - GNUNET_RECLAIM_get_attributes_next (handle->attr_it); + if ((NULL == reference->name) || (NULL == reference->reference_value)) + { + return; + } + scope_variables = GNUNET_strdup (handle->oidc->scope); + scope_variable = strtok (scope_variables, delimiter); + while (NULL != scope_variable) + { + if (0 == strcmp (reference->name, scope_variable)) + break; + scope_variable = strtok (NULL, delimiter); + } + if (NULL == scope_variable) + { + GNUNET_free (scope_variables); + return; + } GNUNET_free (scope_variables); - return; + struct GNUNET_RECLAIM_ATTRIBUTE_ClaimListEntry *le2; + le2 = GNUNET_new (struct GNUNET_RECLAIM_ATTRIBUTE_ClaimListEntry); + le = GNUNET_new (struct GNUNET_RECLAIM_ATTRIBUTE_ClaimListEntry); + le->claim = NULL; + le->reference = NULL; + le->attest = GNUNET_RECLAIM_ATTESTATION_claim_new (attest->name, + attest->type, + attest->data, + attest->data_size); + le->attest->id = attest->id; + le2->attest = NULL; + le2->claim = NULL; + le2->reference = GNUNET_RECLAIM_ATTESTATION_reference_new (reference->name, + reference-> + reference_value); + le2->reference->id = reference->id; + le2->reference->id_attest = reference->id_attest; + GNUNET_CONTAINER_DLL_insert (handle->attr_list->list_head, + handle->attr_list->list_tail, + le); + GNUNET_CONTAINER_DLL_insert (handle->attr_list->list_head, + handle->attr_list->list_tail, + le2); + } + else if (NULL != attr) + { + if ((NULL == attr->name) || (NULL == attr->data)) + { + GNUNET_RECLAIM_get_attributes_next (handle->attr_it); + return; + } + scope_variables = GNUNET_strdup (handle->oidc->scope); + scope_variable = strtok (scope_variables, delimiter); + while (NULL != scope_variable) + { + if (0 == strcmp (attr->name, scope_variable)) + break; + scope_variable = strtok (NULL, delimiter); + } + if (NULL == scope_variable) + { + GNUNET_RECLAIM_get_attributes_next (handle->attr_it); + GNUNET_free (scope_variables); + return; + } + GNUNET_free (scope_variables); + le = GNUNET_new (struct GNUNET_RECLAIM_ATTRIBUTE_ClaimListEntry); + le->reference = NULL; + le->attest = NULL; + le->claim = GNUNET_RECLAIM_ATTRIBUTE_claim_new (attr->name, + attr->type, + attr->data, + attr->data_size); + le->claim->id = attr->id; + le->claim->flag = attr->flag; + + GNUNET_CONTAINER_DLL_insert (handle->attr_list->list_head, + handle->attr_list->list_tail, + le); + GNUNET_RECLAIM_get_attributes_next (handle->attr_it); } - GNUNET_free (scope_variables); - - le = GNUNET_new (struct GNUNET_RECLAIM_ATTRIBUTE_ClaimListEntry); - le->claim = GNUNET_RECLAIM_ATTRIBUTE_claim_new (attr->name, - attr->type, - attr->data, - attr->data_size); - le->claim->id = attr->id; - le->claim->version = attr->version; - GNUNET_CONTAINER_DLL_insert (handle->attr_list->list_head, - handle->attr_list->list_tail, - le); - GNUNET_RECLAIM_get_attributes_next (handle->attr_it); } @@ -1304,6 +1377,9 @@ build_authz_response (void *cls) // OPTIONAL value: nonce handle->oidc->nonce = get_url_parameter_copy (handle, OIDC_NONCE_KEY); + // OPTIONAL value: claims + handle->oidc->claims = get_url_parameter_copy (handle, OIDC_CLAIMS_KEY); + // TODO check other values if needed number_of_ignored_parameter = sizeof(OIDC_ignored_parameter_array) / sizeof(char *); @@ -1454,6 +1530,9 @@ authorize_endpoint (struct GNUNET_REST_RequestHandle *con_handle, handle->ego_entry = handle->ego_tail; } } + handle->oidc->scope = get_url_parameter_copy (handle, OIDC_SCOPE_KEY); + GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Scope: %s\n",GNUNET_strdup ( + handle->oidc->scope)); if (NULL == handle->tld) GNUNET_CONFIGURATION_iterate_section_values (cfg, "gns", tld_iter, handle); if (NULL == handle->tld) @@ -1857,28 +1936,97 @@ token_endpoint (struct GNUNET_REST_RequestHandle *con_handle, /** - * Collects claims and stores them in handle - */ + * Collects claims and stores them in handle + */ static void consume_ticket (void *cls, const struct GNUNET_CRYPTO_EcdsaPublicKey *identity, - const struct GNUNET_RECLAIM_ATTRIBUTE_Claim *attr) + const struct GNUNET_RECLAIM_ATTRIBUTE_Claim *attr, + const struct GNUNET_RECLAIM_ATTESTATION_Claim *attest, + const struct GNUNET_RECLAIM_ATTESTATION_REFERENCE *reference) { struct RequestHandle *handle = cls; - char *tmp_value; - json_t *value; - if (NULL == identity) { GNUNET_SCHEDULER_add_now (&return_userinfo_response, handle); return; } - tmp_value = GNUNET_RECLAIM_ATTRIBUTE_value_to_string (attr->type, - attr->data, - attr->data_size); - value = json_string (tmp_value); - json_object_set_new (handle->oidc->response, attr->name, value); - GNUNET_free (tmp_value); + if (NULL != attr) + { + char *tmp_value; + json_t *value; + tmp_value = GNUNET_RECLAIM_ATTRIBUTE_value_to_string (attr->type, + attr->data, + attr->data_size); + value = json_string (tmp_value); + json_object_set_new (handle->oidc->response, attr->name, value); + GNUNET_free (tmp_value); + } + else if ((NULL != attest) && (NULL != reference)) + { + json_t *claim_sources; + json_t *claim_sources_jwt; + json_t *claim_names; + char *attest_val_str; + claim_sources=json_object_get(handle->oidc->response,"_claim_sources"); + claim_names=json_object_get(handle->oidc->response,"_claim_names"); + attest_val_str = GNUNET_RECLAIM_ATTESTATION_value_to_string (attest->type, + attest->data, + attest-> + data_size); + if ((NULL == claim_sources) && (NULL == claim_names) ) + { + claim_sources = json_object (); + claim_names = json_object (); + } + char *source_name; + int i = 0; + GNUNET_asprintf (&source_name,"src%d",i); + while (NULL != (claim_sources_jwt = json_object_get (claim_sources, + source_name))) + { + if (0 == strcmp (json_string_value (json_object_get (claim_sources_jwt, + "JWT")), + attest_val_str)) + { + // Adapt only the claim names + json_object_set_new (claim_names, reference->name, json_string ( + source_name)); + json_object_set (handle->oidc->response, "_claim_names",claim_names); + handle->oidc->response = json_deep_copy(handle->oidc->response); + break; + } + i++; + GNUNET_asprintf (&source_name,"src%d",i); + } + + // Create new one + if (NULL == claim_sources_jwt) + { + claim_sources_jwt = json_object (); + // Set the JWT for names + json_object_set_new (claim_names, reference->name, json_string ( + source_name)); + // Set the JWT for the inner source + json_object_set_new (claim_sources_jwt, "JWT", json_string ( + attest_val_str)); + // Set the JWT for the source + json_object_set_new (claim_sources, source_name,claim_sources_jwt); + // Set as claims + json_object_set (handle->oidc->response, "_claim_names", claim_names); + json_object_set (handle->oidc->response, "_claim_sources",claim_sources); + handle->oidc->response = json_deep_copy(handle->oidc->response); + } + + json_decref (claim_sources); + json_decref (claim_names); + json_decref (claim_sources_jwt); + GNUNET_free (attest_val_str); + } + else + { + // REMARK: We should not find any claim, one of attest/ref is NULL + } } diff --git a/src/reclaim/plugin_rest_reclaim.c b/src/reclaim/plugin_rest_reclaim.c index 9a75b2d16..dcda75b65 100644 --- a/src/reclaim/plugin_rest_reclaim.c +++ b/src/reclaim/plugin_rest_reclaim.c @@ -37,7 +37,6 @@ #include "gnunet_rest_plugin.h" #include "gnunet_signatures.h" #include "json_reclaim.h" - /** * REST root namespace */ @@ -49,6 +48,11 @@ #define GNUNET_REST_API_NS_RECLAIM_ATTRIBUTES "/reclaim/attributes" /** + * Attestation namespace + */ +#define GNUNET_REST_API_NS_RECLAIM_ATTESTATION_REFERENCE "/reclaim/attestation" + +/** * Ticket namespace */ #define GNUNET_REST_API_NS_IDENTITY_TICKETS "/reclaim/tickets" @@ -272,6 +276,8 @@ cleanup_handle (struct RequestHandle *handle) claim_tmp = claim_entry; claim_entry = claim_entry->next; GNUNET_free (claim_tmp->claim); + GNUNET_free (claim_tmp->attest); + GNUNET_free (claim_tmp->reference); GNUNET_free (claim_tmp); } GNUNET_free (handle->attr_list); @@ -360,6 +366,21 @@ finished_cont (void *cls, int32_t success, const char *emsg) GNUNET_SCHEDULER_add_now (&cleanup_handle_delayed, handle); } +static void +delete_finished_cb (void *cls, int32_t success, const char *emsg) +{ + struct RequestHandle *handle = cls; + struct MHD_Response *resp; + + resp = GNUNET_REST_create_response (emsg); + if (GNUNET_OK != success) + { + GNUNET_SCHEDULER_add_now (&do_error, handle); + return; + } + handle->proc (handle->proc_cls, resp, MHD_HTTP_OK); + GNUNET_SCHEDULER_add_now (&cleanup_handle_delayed, handle); +} /** * Return attributes for identity @@ -434,6 +455,661 @@ ticket_collect (void *cls, const struct GNUNET_RECLAIM_Ticket *ticket) } +static void +add_attestation_ref_cont (struct GNUNET_REST_RequestHandle *con_handle, + const char *url, + void *cls) +{ + struct RequestHandle *handle = cls; + const struct GNUNET_CRYPTO_EcdsaPrivateKey *identity_priv; + const char *identity; + struct EgoEntry *ego_entry; + struct GNUNET_RECLAIM_ATTESTATION_REFERENCE *attribute; + struct GNUNET_TIME_Relative exp; + char term_data[handle->rest_handle->data_size + 1]; + json_t *data_json; + json_error_t err; + struct GNUNET_JSON_Specification attrspec[] = + { GNUNET_RECLAIM_JSON_spec_claim_attest_ref (&attribute), + GNUNET_JSON_spec_end () }; + GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, + "Adding an attestation reference for %s.\n", + handle->url); + if (strlen (GNUNET_REST_API_NS_RECLAIM_ATTESTATION_REFERENCE) + strlen ( + "reference/") + 1 >= strlen ( + handle->url)) + { + GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "No identity given.\n"); + GNUNET_SCHEDULER_add_now (&do_error, handle); + return; + } + identity = handle->url + strlen ( + GNUNET_REST_API_NS_RECLAIM_ATTESTATION_REFERENCE) + strlen ("reference/") + + 1; + for (ego_entry = handle->ego_head; NULL != ego_entry; + ego_entry = ego_entry->next) + if (0 == strcmp (identity, ego_entry->identifier)) + break; + if (NULL == ego_entry) + { + GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "Identity unknown (%s)\n", identity); + return; + } + identity_priv = GNUNET_IDENTITY_ego_get_private_key (ego_entry->ego); + if (0 >= handle->rest_handle->data_size) + { + GNUNET_SCHEDULER_add_now (&do_error, handle); + return; + } + + term_data[handle->rest_handle->data_size] = '\0'; + GNUNET_memcpy (term_data, + handle->rest_handle->data, + handle->rest_handle->data_size); + data_json = json_loads (term_data, JSON_DECODE_ANY, &err); + GNUNET_assert (GNUNET_OK == + GNUNET_JSON_parse (data_json, attrspec, NULL, NULL)); + json_decref (data_json); + if (NULL == attribute) + { + GNUNET_log (GNUNET_ERROR_TYPE_ERROR, + "Unable to parse attestation reference from %s\n", + term_data); + GNUNET_SCHEDULER_add_now (&do_error, handle); + return; + } + /** + * New ID for attribute + */ + if (0 == attribute->id) + attribute->id = attribute->id_attest; + handle->idp = GNUNET_RECLAIM_connect (cfg); + exp = GNUNET_TIME_UNIT_HOURS; + handle->idp_op = GNUNET_RECLAIM_attestation_reference_store (handle->idp, + identity_priv, + attribute, + &exp, + &finished_cont, + handle); + GNUNET_JSON_parse_free (attrspec); +} + +static void +parse_attestation_cont (struct GNUNET_REST_RequestHandle *con_handle, + const char *url, + void *cls) +{ + struct RequestHandle *handle = cls; + + char term_data[handle->rest_handle->data_size + 1]; + json_t *data_json; + json_error_t err; + int unpack_state; + struct MHD_Response *resp; + char *val_str = NULL; + const char *type_str = NULL; + term_data[handle->rest_handle->data_size] = '\0'; + GNUNET_memcpy (term_data, + handle->rest_handle->data, + handle->rest_handle->data_size); + data_json = json_loads (term_data, JSON_DECODE_ANY, &err); + GNUNET_assert (NULL != data_json); + if (! json_is_object (data_json)) + { + GNUNET_log (GNUNET_ERROR_TYPE_ERROR, + "Error json is not array nor object!\n"); + GNUNET_SCHEDULER_add_now (&do_error, handle); + return; + } + unpack_state = json_unpack (data_json, + "{s:s, s:s!}", + "value", + &val_str, + "type", + &type_str); + if ((0 != unpack_state) || (NULL == val_str) || (NULL == type_str)) + { + GNUNET_log (GNUNET_ERROR_TYPE_ERROR, + "Error json object has a wrong format!\n"); + GNUNET_SCHEDULER_add_now (&do_error, handle); + return; + } + if (0 == strcmp (type_str, "JWT")) + { + // The value is a JWT + char *decoded_jwt; + char delim[] = "."; + char *jwt_body = strtok (val_str, delim); + jwt_body = strtok (NULL, delim); + GNUNET_STRINGS_base64_decode (jwt_body, strlen (jwt_body), + (void **) &decoded_jwt); + resp = GNUNET_REST_create_response (decoded_jwt); + handle->proc (handle->proc_cls, resp, MHD_HTTP_OK); + GNUNET_free (decoded_jwt); + } + else + { + GNUNET_log (GNUNET_ERROR_TYPE_ERROR, + "Error requested parsing type not supported!\n"); + GNUNET_SCHEDULER_add_now (&do_error, handle); + return; + } + cleanup_handle (handle); + json_decref (data_json); +} + +static void +add_attestation_cont (struct GNUNET_REST_RequestHandle *con_handle, + const char *url, + void *cls) +{ + struct RequestHandle *handle = cls; + /* Check for substring "reference" */ + if (strlen (GNUNET_REST_API_NS_RECLAIM_ATTESTATION_REFERENCE) < strlen ( + handle->url)) + { + if ( strncmp ("reference/", (handle->url + strlen ( + GNUNET_REST_API_NS_RECLAIM_ATTESTATION_REFERENCE) + + 1), strlen ( + "reference/")) == 0) + { + add_attestation_ref_cont (con_handle,url,cls); + return; + } + } + /* Check for substring "parse" */ + if (strlen (GNUNET_REST_API_NS_RECLAIM_ATTESTATION_REFERENCE) < strlen ( + handle->url)) + { + if ( strncmp ("parse", (handle->url + strlen ( + GNUNET_REST_API_NS_RECLAIM_ATTESTATION_REFERENCE) + + 1), strlen ( + "parse")) == 0) + { + parse_attestation_cont (con_handle,url,cls); + return; + } + } + const struct GNUNET_CRYPTO_EcdsaPrivateKey *identity_priv; + const char *identity; + struct EgoEntry *ego_entry; + struct GNUNET_RECLAIM_ATTESTATION_Claim *attribute; + struct GNUNET_TIME_Relative exp; + char term_data[handle->rest_handle->data_size + 1]; + json_t *data_json; + json_error_t err; + struct GNUNET_JSON_Specification attrspec[] = + { GNUNET_RECLAIM_JSON_spec_claim_attest (&attribute), + GNUNET_JSON_spec_end () }; + + GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, + "Adding an attestation for %s.\n", + handle->url); + if (strlen (GNUNET_REST_API_NS_RECLAIM_ATTESTATION_REFERENCE) >= strlen ( + handle->url)) + { + GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "No identity given.\n"); + GNUNET_SCHEDULER_add_now (&do_error, handle); + return; + } + identity = handle->url + strlen ( + GNUNET_REST_API_NS_RECLAIM_ATTESTATION_REFERENCE) + 1; + + for (ego_entry = handle->ego_head; NULL != ego_entry; + ego_entry = ego_entry->next) + if (0 == strcmp (identity, ego_entry->identifier)) + break; + + if (NULL == ego_entry) + { + GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "Identity unknown (%s)\n", identity); + return; + } + identity_priv = GNUNET_IDENTITY_ego_get_private_key (ego_entry->ego); + + if (0 >= handle->rest_handle->data_size) + { + GNUNET_SCHEDULER_add_now (&do_error, handle); + return; + } + + term_data[handle->rest_handle->data_size] = '\0'; + GNUNET_memcpy (term_data, + handle->rest_handle->data, + handle->rest_handle->data_size); + data_json = json_loads (term_data, JSON_DECODE_ANY, &err); + GNUNET_assert (GNUNET_OK == + GNUNET_JSON_parse (data_json, attrspec, NULL, NULL)); + json_decref (data_json); + if (NULL == attribute) + { + GNUNET_log (GNUNET_ERROR_TYPE_ERROR, + "Unable to parse attestation from %s\n", + term_data); + GNUNET_SCHEDULER_add_now (&do_error, handle); + return; + } + /** + * New ID for attribute + */ + if (0 == attribute->id) + attribute->id = + GNUNET_CRYPTO_random_u64 (GNUNET_CRYPTO_QUALITY_STRONG, UINT64_MAX); + handle->idp = GNUNET_RECLAIM_connect (cfg); + exp = GNUNET_TIME_UNIT_HOURS; + handle->idp_op = GNUNET_RECLAIM_attestation_store (handle->idp, + identity_priv, + attribute, + &exp, + &finished_cont, + handle); + GNUNET_JSON_parse_free (attrspec); +} + +/** + * Collect all references for an ego + * + */ +static void +ref_collect (void *cls, + const struct GNUNET_CRYPTO_EcdsaPublicKey *identity, + const struct GNUNET_RECLAIM_ATTRIBUTE_Claim *attr, + const struct GNUNET_RECLAIM_ATTESTATION_Claim *attest, + const struct GNUNET_RECLAIM_ATTESTATION_REFERENCE *reference) +{ + struct RequestHandle *handle = cls; + json_t *attr_obj; + char *id_str; + char *id_attest_str; + + if (NULL == reference) + { + GNUNET_RECLAIM_get_attributes_next (handle->attr_it); + return; + } + + if ((NULL == reference->name) || (NULL == reference->reference_value)) + { + return; + } + + GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Adding reference: %s\n", + reference->name); + attr_obj = json_object (); + json_object_set_new (attr_obj, "name", json_string (reference->name)); + json_object_set_new (attr_obj, "ref_value", json_string ( + reference->reference_value)); + id_str = GNUNET_STRINGS_data_to_string_alloc (&reference->id, + sizeof(uint64_t)); + id_attest_str = GNUNET_STRINGS_data_to_string_alloc (&reference->id_attest, + sizeof(uint64_t)); + json_object_set_new (attr_obj, "id", json_string (id_str)); + json_object_set_new (attr_obj, "ref_id", json_string (id_attest_str)); + json_array_append (handle->resp_object, attr_obj); + json_decref (attr_obj); +} + +/** + * Lists references for identity request + * + * @param con_handle the connection handle + * @param url the url + * @param cls the RequestHandle + */ +static void +list_reference_cont (struct GNUNET_REST_RequestHandle *con_handle, + const char *url, + void *cls) +{ + const struct GNUNET_CRYPTO_EcdsaPrivateKey *priv_key; + struct RequestHandle *handle = cls; + struct EgoEntry *ego_entry; + char *identity; + + GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, + "Getting references for %s.\n", + handle->url); + if (strlen (GNUNET_REST_API_NS_RECLAIM_ATTESTATION_REFERENCE) + strlen ( + "reference/") + 1 >= strlen ( + handle->url)) + { + GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "No identity given.\n"); + GNUNET_SCHEDULER_add_now (&do_error, handle); + return; + } + identity = handle->url + strlen ( + GNUNET_REST_API_NS_RECLAIM_ATTESTATION_REFERENCE) + strlen ("reference/") + + 1; + for (ego_entry = handle->ego_head; NULL != ego_entry; + ego_entry = ego_entry->next) + if (0 == strcmp (identity, ego_entry->identifier)) + break; + handle->resp_object = json_array (); + + if (NULL == ego_entry) + { + // Done + GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Ego %s not found.\n", identity); + GNUNET_SCHEDULER_add_now (&return_response, handle); + return; + } + priv_key = GNUNET_IDENTITY_ego_get_private_key (ego_entry->ego); + handle->idp = GNUNET_RECLAIM_connect (cfg); + handle->attr_it = GNUNET_RECLAIM_get_attributes_start (handle->idp, + priv_key, + &collect_error_cb, + handle, + &ref_collect, + handle, + &collect_finished_cb, + handle); +} + +/** + * Collect all attestations for an ego + * + */ +static void +attest_collect (void *cls, + const struct GNUNET_CRYPTO_EcdsaPublicKey *identity, + const struct GNUNET_RECLAIM_ATTRIBUTE_Claim *attr, + const struct GNUNET_RECLAIM_ATTESTATION_Claim *attest, + const struct GNUNET_RECLAIM_ATTESTATION_REFERENCE *reference) +{ + struct RequestHandle *handle = cls; + json_t *attr_obj; + const char *type; + char *tmp_value; + char *id_str; + + + if (NULL != reference) + { + GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, + "Attestation Collection with Reference\n"); + return; + } + if (NULL == attest) + { + GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, + "Attestation Collection with empty Attestation\n"); + GNUNET_RECLAIM_get_attributes_next (handle->attr_it); + return; + } + + if ((NULL == attest->name) || (NULL == attest->data)) + { + GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, + "Attestation Collection with empty Name/Value\n"); + GNUNET_RECLAIM_get_attributes_next (handle->attr_it); + return; + } + + GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Adding attestation: %s\n", + attest->name); + + tmp_value = GNUNET_RECLAIM_ATTESTATION_value_to_string (attest->type, + attest->data, + attest->data_size); + attr_obj = json_object (); + json_object_set_new (attr_obj, "value", json_string (tmp_value)); + json_object_set_new (attr_obj, "name", json_string (attest->name)); + type = GNUNET_RECLAIM_ATTESTATION_number_to_typename (attest->type); + json_object_set_new (attr_obj, "type", json_string (type)); + id_str = GNUNET_STRINGS_data_to_string_alloc (&attest->id, sizeof(uint64_t)); + json_object_set_new (attr_obj, "id", json_string (id_str)); + json_array_append (handle->resp_object, attr_obj); + json_decref (attr_obj); + GNUNET_free (tmp_value); + GNUNET_RECLAIM_get_attributes_next (handle->attr_it); +} + + +/** + * Lists attestation for identity request + * + * @param con_handle the connection handle + * @param url the url + * @param cls the RequestHandle + */ +static void +list_attestation_cont (struct GNUNET_REST_RequestHandle *con_handle, + const char *url, + void *cls) +{ + struct RequestHandle *handle = cls; + /* Check for substring "reference" */ + if (strlen (GNUNET_REST_API_NS_RECLAIM_ATTESTATION_REFERENCE) < strlen ( + handle->url)) + { + if ( strncmp ("reference/", (handle->url + strlen ( + GNUNET_REST_API_NS_RECLAIM_ATTESTATION_REFERENCE) + + 1), strlen ( + "reference/")) == 0) + { + list_reference_cont (con_handle,url,cls); + return; + } + } + const struct GNUNET_CRYPTO_EcdsaPrivateKey *priv_key; + struct EgoEntry *ego_entry; + char *identity; + + GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, + "Getting attestations for %s.\n", + handle->url); + if (strlen (GNUNET_REST_API_NS_RECLAIM_ATTESTATION_REFERENCE) >= strlen ( + handle->url)) + { + GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "No identity given.\n"); + GNUNET_SCHEDULER_add_now (&do_error, handle); + return; + } + identity = handle->url + strlen ( + GNUNET_REST_API_NS_RECLAIM_ATTESTATION_REFERENCE) + 1; + + for (ego_entry = handle->ego_head; NULL != ego_entry; + ego_entry = ego_entry->next) + if (0 == strcmp (identity, ego_entry->identifier)) + break; + handle->resp_object = json_array (); + + + if (NULL == ego_entry) + { + // Done + GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Ego %s not found.\n", identity); + GNUNET_SCHEDULER_add_now (&return_response, handle); + return; + } + priv_key = GNUNET_IDENTITY_ego_get_private_key (ego_entry->ego); + handle->idp = GNUNET_RECLAIM_connect (cfg); + handle->attr_it = GNUNET_RECLAIM_get_attributes_start (handle->idp, + priv_key, + &collect_error_cb, + handle, + &attest_collect, + handle, + &collect_finished_cb, + handle); +} + +/** + * Deletes reference from an identity + * + * @param con_handle the connection handle + * @param url the url + * @param cls the RequestHandle + */ +static void +delete_attestation_ref_cont (struct GNUNET_REST_RequestHandle *con_handle, + const char *url, + void *cls) +{ + struct RequestHandle *handle = cls; + const struct GNUNET_CRYPTO_EcdsaPrivateKey *priv_key; + struct GNUNET_RECLAIM_ATTESTATION_REFERENCE *attr; + struct EgoEntry *ego_entry; + char *identity; + char *identity_id_str; + char *id; + char term_data[handle->rest_handle->data_size + 1]; + json_t *data_json; + json_error_t err; + + struct GNUNET_JSON_Specification attrspec[] = + { GNUNET_RECLAIM_JSON_spec_claim_attest_ref (&attr), + GNUNET_JSON_spec_end () }; + GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, + "Deleting attestation reference.\n"); + if (strlen (GNUNET_REST_API_NS_RECLAIM_ATTESTATION_REFERENCE) + strlen ( + "reference/") + 1 >= strlen ( + handle->url)) + { + GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "No identity given.\n"); + GNUNET_SCHEDULER_add_now (&do_error, handle); + return; + } + identity_id_str = strdup (handle->url + strlen ( + GNUNET_REST_API_NS_RECLAIM_ATTESTATION_REFERENCE) + + strlen ("reference/") + + 1); + identity = strtok (identity_id_str, "/"); + id = strtok (NULL, "/"); + + if ((NULL == identity) || (NULL == id)) + { + GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "Malformed request.\n"); + GNUNET_SCHEDULER_add_now (&do_error, handle); + return; + } + for (ego_entry = handle->ego_head; NULL != ego_entry; + ego_entry = ego_entry->next) + if (0 == strcmp (identity, ego_entry->identifier)) + break; + handle->resp_object = json_array (); + if (NULL == ego_entry) + { + GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Ego %s not found.\n", identity); + GNUNET_SCHEDULER_add_now (&return_response, handle); + return; + } + priv_key = GNUNET_IDENTITY_ego_get_private_key (ego_entry->ego); + if (0 >= handle->rest_handle->data_size) + { + GNUNET_SCHEDULER_add_now (&do_error, handle); + return; + } + + term_data[handle->rest_handle->data_size] = '\0'; + GNUNET_memcpy (term_data, + handle->rest_handle->data, + handle->rest_handle->data_size); + data_json = json_loads (term_data, JSON_DECODE_ANY, &err); + GNUNET_assert (GNUNET_OK == + GNUNET_JSON_parse (data_json, attrspec, NULL, NULL)); + json_decref (data_json); + if (NULL == attr) + { + GNUNET_log (GNUNET_ERROR_TYPE_ERROR, + "Unable to parse attestation reference from %s\n", + term_data); + GNUNET_SCHEDULER_add_now (&do_error, handle); + return; + } + GNUNET_STRINGS_string_to_data (id, strlen (id), &attr->id, sizeof(uint64_t)); + + handle->idp = GNUNET_RECLAIM_connect (cfg); + handle->idp_op = GNUNET_RECLAIM_attestation_reference_delete (handle->idp, + priv_key, + attr, + & + delete_finished_cb, + handle); + GNUNET_JSON_parse_free (attrspec); +} + + +/** + * Deletes attestation from an identity + * + * @param con_handle the connection handle + * @param url the url + * @param cls the RequestHandle + */ +static void +delete_attestation_cont (struct GNUNET_REST_RequestHandle *con_handle, + const char *url, + void *cls) +{ + struct RequestHandle *handle = cls; + /* Check for substring "reference" */ + if (strlen (GNUNET_REST_API_NS_RECLAIM_ATTESTATION_REFERENCE) < strlen ( + handle->url)) + { + if ( strncmp ("reference", (handle->url + strlen ( + GNUNET_REST_API_NS_RECLAIM_ATTESTATION_REFERENCE) + + 1), strlen ( + "reference")) == 0) + { + delete_attestation_ref_cont (con_handle,url,cls); + return; + } + } + const struct GNUNET_CRYPTO_EcdsaPrivateKey *priv_key; + struct GNUNET_RECLAIM_ATTESTATION_Claim attr; + struct EgoEntry *ego_entry; + char *identity_id_str; + char *identity; + char *id; + + GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Deleting attestation.\n"); + if (strlen (GNUNET_REST_API_NS_RECLAIM_ATTESTATION_REFERENCE) >= strlen ( + handle->url)) + { + GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "No identity given.\n"); + GNUNET_SCHEDULER_add_now (&do_error, handle); + return; + } + identity_id_str = + strdup (handle->url + strlen ( + GNUNET_REST_API_NS_RECLAIM_ATTESTATION_REFERENCE) + 1); + identity = strtok (identity_id_str, "/"); + id = strtok (NULL, "/"); + if ((NULL == identity) || (NULL == id)) + { + GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "Malformed request.\n"); + GNUNET_free (identity_id_str); + GNUNET_SCHEDULER_add_now (&do_error, handle); + return; + } + + for (ego_entry = handle->ego_head; NULL != ego_entry; + ego_entry = ego_entry->next) + if (0 == strcmp (identity, ego_entry->identifier)) + break; + handle->resp_object = json_array (); + if (NULL == ego_entry) + { + // Done + GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Ego %s not found.\n", identity); + GNUNET_free (identity_id_str); + GNUNET_SCHEDULER_add_now (&return_response, handle); + return; + } + priv_key = GNUNET_IDENTITY_ego_get_private_key (ego_entry->ego); + handle->idp = GNUNET_RECLAIM_connect (cfg); + memset (&attr, 0, sizeof(struct GNUNET_RECLAIM_ATTESTATION_Claim)); + GNUNET_STRINGS_string_to_data (id, strlen (id), &attr.id, sizeof(uint64_t)); + attr.name = ""; + handle->idp_op = GNUNET_RECLAIM_attestation_delete (handle->idp, + priv_key, + &attr, + &delete_finished_cb, + handle); + GNUNET_free (identity_id_str); +} + /** * List tickets for identity request * @@ -568,6 +1244,72 @@ add_attribute_cont (struct GNUNET_REST_RequestHandle *con_handle, GNUNET_JSON_parse_free (attrspec); } +/** + * Parse a JWT and return the respective claim value as Attribute + * + * @param attest the jwt attestation + * @param claim the name of the claim in the JWT + * + * @return a GNUNET_RECLAIM_ATTRIBUTE_Claim, containing the new value + */ +struct GNUNET_RECLAIM_ATTRIBUTE_Claim * +parse_jwt (const struct GNUNET_RECLAIM_ATTESTATION_Claim *attest, + const char *claim) +{ + char *jwt_string; + struct GNUNET_RECLAIM_ATTRIBUTE_Claim *attr; + char delim[] = "."; + const char *type_str = NULL; + const char *val_str = NULL; + char *data; + size_t data_size; + uint32_t type; + GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Parsing JWT attributes.\n"); + char *decoded_jwt; + json_t *json_val; + json_error_t *json_err = NULL; + + jwt_string = GNUNET_RECLAIM_ATTESTATION_value_to_string (attest->type, + attest->data, + attest->data_size); + char *jwt_body = strtok (jwt_string, delim); + jwt_body = strtok (NULL, delim); + GNUNET_STRINGS_base64_decode (jwt_body, strlen (jwt_body), + (void **) &decoded_jwt); + json_val = json_loads (decoded_jwt, JSON_DECODE_ANY, json_err); + const char *key; + json_t *value; + json_object_foreach (json_val, key, value) { + if (0 == strcasecmp (key,claim)) + { + val_str = json_dumps (value, JSON_ENCODE_ANY); + } + } + type_str = "String"; + type = GNUNET_RECLAIM_ATTRIBUTE_typename_to_number (type_str); + if (GNUNET_SYSERR ==(GNUNET_RECLAIM_ATTRIBUTE_string_to_value (type,val_str, + (void **) &data, + &data_size))) + { + GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, + "Attribute value from JWT Parser invalid!\n"); + GNUNET_RECLAIM_ATTRIBUTE_string_to_value (type, + "Error: Referenced Claim Name not Found", + (void **) &data, + &data_size); + attr = GNUNET_RECLAIM_ATTRIBUTE_claim_new (claim, type, data, data_size); + attr->id = attest->id; + attr->flag = 1; + } + else + { + attr = GNUNET_RECLAIM_ATTRIBUTE_claim_new (claim, type, data, data_size); + attr->id = attest->id; + attr->flag = 1; + } + return attr; +} + /** * Collect all attributes for an ego @@ -576,40 +1318,93 @@ add_attribute_cont (struct GNUNET_REST_RequestHandle *con_handle, static void attr_collect (void *cls, const struct GNUNET_CRYPTO_EcdsaPublicKey *identity, - const struct GNUNET_RECLAIM_ATTRIBUTE_Claim *attr) + const struct GNUNET_RECLAIM_ATTRIBUTE_Claim *attr, + const struct GNUNET_RECLAIM_ATTESTATION_Claim *attest, + const struct GNUNET_RECLAIM_ATTESTATION_REFERENCE *reference) { struct RequestHandle *handle = cls; json_t *attr_obj; const char *type; - char *tmp_value; char *id_str; - if ((NULL == attr->name) || (NULL == attr->data)) + if ((NULL == attr) && (NULL == reference)) { + GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, + "Attribute Collection with empty Attribute/Reference\n"); GNUNET_RECLAIM_get_attributes_next (handle->attr_it); return; } - GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Adding attribute: %s\n", attr->name); - - tmp_value = GNUNET_RECLAIM_ATTRIBUTE_value_to_string (attr->type, - attr->data, - attr->data_size); + if (NULL == attr) + { - attr_obj = json_object (); - json_object_set_new (attr_obj, "value", json_string (tmp_value)); - json_object_set_new (attr_obj, "name", json_string (attr->name)); - type = GNUNET_RECLAIM_ATTRIBUTE_number_to_typename (attr->type); - json_object_set_new (attr_obj, "type", json_string (type)); - id_str = GNUNET_STRINGS_data_to_string_alloc (&attr->id, sizeof(uint64_t)); - json_object_set_new (attr_obj, "id", json_string (id_str)); - json_array_append (handle->resp_object, attr_obj); - json_decref (attr_obj); - GNUNET_free (tmp_value); - GNUNET_RECLAIM_get_attributes_next (handle->attr_it); + if ((NULL == reference->name) || (NULL == reference->reference_value)) + { + GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, + "Attribute Collection with empty Reference Name/Value\n"); + return; + } + struct GNUNET_RECLAIM_ATTRIBUTE_Claim *attr2; + attr2 = parse_jwt (attest, reference->reference_value); + if (NULL == attr2) + { + GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, + "Attribute Collection with unparsed Attestation\n"); + return; + } + attr2->name = reference->name; + GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Adding reference as attribute: %s\n", + reference->name); + char *tmp_value; + tmp_value = GNUNET_RECLAIM_ATTRIBUTE_value_to_string (attr2->type, + attr2->data, + attr2->data_size); + attr_obj = json_object (); + + json_object_set_new (attr_obj, "value", json_string (tmp_value)); + json_object_set_new (attr_obj, "name", json_string (attr2->name)); + json_object_set_new (attr_obj, "flag", json_string ("1")); + type = GNUNET_RECLAIM_ATTRIBUTE_number_to_typename (attr2->type); + json_object_set_new (attr_obj, "type", json_string (type)); + id_str = GNUNET_STRINGS_data_to_string_alloc (&attr2->id, sizeof(uint64_t)); + json_object_set_new (attr_obj, "id", json_string (id_str)); + json_array_append (handle->resp_object, attr_obj); + json_decref (attr_obj); + GNUNET_free (tmp_value); + } + else + { + if ((NULL == attr->name) || (NULL == attr->data)) + { + GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, + "Attribute Collection with empty Attribute Name/Value\n"); + GNUNET_RECLAIM_get_attributes_next (handle->attr_it); + return; + } + char *tmp_value; + char *flag_str; + GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Adding attribute: %s\n", attr->name); + + tmp_value = GNUNET_RECLAIM_ATTRIBUTE_value_to_string (attr->type, + attr->data, + attr->data_size); + + attr_obj = json_object (); + json_object_set_new (attr_obj, "value", json_string (tmp_value)); + json_object_set_new (attr_obj, "name", json_string (attr->name)); + GNUNET_asprintf (&flag_str,"%d",attr->flag); + json_object_set_new (attr_obj, "flag", json_string (flag_str)); + type = GNUNET_RECLAIM_ATTRIBUTE_number_to_typename (attr->type); + json_object_set_new (attr_obj, "type", json_string (type)); + id_str = GNUNET_STRINGS_data_to_string_alloc (&attr->id, sizeof(uint64_t)); + json_object_set_new (attr_obj, "id", json_string (id_str)); + json_array_append (handle->resp_object, attr_obj); + json_decref (attr_obj); + GNUNET_free (tmp_value); + GNUNET_RECLAIM_get_attributes_next (handle->attr_it); + } } - /** * List attributes for identity request * @@ -665,23 +1460,6 @@ list_attribute_cont (struct GNUNET_REST_RequestHandle *con_handle, } -static void -delete_finished_cb (void *cls, int32_t success, const char *emsg) -{ - struct RequestHandle *handle = cls; - struct MHD_Response *resp; - - resp = GNUNET_REST_create_response (emsg); - if (GNUNET_OK != success) - { - GNUNET_SCHEDULER_add_now (&do_error, handle); - return; - } - handle->proc (handle->proc_cls, resp, MHD_HTTP_OK); - GNUNET_SCHEDULER_add_now (&cleanup_handle_delayed, handle); -} - - /** * List attributes for identity request * @@ -825,7 +1603,9 @@ revoke_ticket_cont (struct GNUNET_REST_RequestHandle *con_handle, static void consume_cont (void *cls, const struct GNUNET_CRYPTO_EcdsaPublicKey *identity, - const struct GNUNET_RECLAIM_ATTRIBUTE_Claim *attr) + const struct GNUNET_RECLAIM_ATTRIBUTE_Claim *attr, + const struct GNUNET_RECLAIM_ATTESTATION_Claim *attest, + const struct GNUNET_RECLAIM_ATTESTATION_REFERENCE *reference) { struct RequestHandle *handle = cls; char *val_str; @@ -969,6 +1749,15 @@ init_cont (struct RequestHandle *handle) GNUNET_REST_API_NS_RECLAIM_ATTRIBUTES, &delete_attribute_cont }, { MHD_HTTP_METHOD_GET, + GNUNET_REST_API_NS_RECLAIM_ATTESTATION_REFERENCE, + &list_attestation_cont }, + { MHD_HTTP_METHOD_POST, + GNUNET_REST_API_NS_RECLAIM_ATTESTATION_REFERENCE, + &add_attestation_cont }, + { MHD_HTTP_METHOD_DELETE, + GNUNET_REST_API_NS_RECLAIM_ATTESTATION_REFERENCE, + &delete_attestation_cont }, + { MHD_HTTP_METHOD_GET, GNUNET_REST_API_NS_IDENTITY_TICKETS, &list_tickets_cont }, { MHD_HTTP_METHOD_POST, diff --git a/src/reclaim/reclaim.h b/src/reclaim/reclaim.h index 8e731812e..ff953a096 100644 --- a/src/reclaim/reclaim.h +++ b/src/reclaim/reclaim.h @@ -153,6 +153,45 @@ struct AttributeResultMessage */ }; +/** + * Reference plus Attestation is returned from the idp. + */ +struct ReferenceResultMessage +{ + /** + * Message header + */ + struct GNUNET_MessageHeader header; + + /** + * Unique identifier for this request (for key collisions). + */ + uint32_t id GNUNET_PACKED; + + /** + * Length of serialized attestation data + */ + uint16_t attest_len GNUNET_PACKED; + + /** + * Length of serialized reference data + */ + uint16_t ref_len GNUNET_PACKED; + + /** + * always zero (for alignment) + */ + uint16_t reserved GNUNET_PACKED; + + /** + * The public key of the identity. + */ + struct GNUNET_CRYPTO_EcdsaPublicKey identity; + + /* followed by: + * serialized reference data + attestation data + */ +}; /** * Start a attribute iteration for the given identity diff --git a/src/reclaim/reclaim_api.c b/src/reclaim/reclaim_api.c index 7d4d7588a..847abb58a 100644 --- a/src/reclaim/reclaim_api.c +++ b/src/reclaim/reclaim_api.c @@ -486,7 +486,7 @@ handle_consume_ticket_result (void *cls, uint32_t r_id = ntohl (msg->id); attrs_len = ntohs (msg->attrs_len); - LOG (GNUNET_ERROR_TYPE_DEBUG, "Processing attribute result.\n"); + GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Processing ticket result.\n"); for (op = h->op_head; NULL != op; op = op->next) @@ -498,22 +498,36 @@ handle_consume_ticket_result (void *cls, { struct GNUNET_RECLAIM_ATTRIBUTE_ClaimList *attrs; struct GNUNET_RECLAIM_ATTRIBUTE_ClaimListEntry *le; + struct GNUNET_RECLAIM_ATTRIBUTE_ClaimListEntry *le2; attrs = GNUNET_RECLAIM_ATTRIBUTE_list_deserialize ((char *) &msg[1], attrs_len); if (NULL != op->ar_cb) { if (NULL == attrs) { - op->ar_cb (op->cls, &msg->identity, NULL); + op->ar_cb (op->cls, &msg->identity, NULL, NULL, NULL); } else { for (le = attrs->list_head; NULL != le; le = le->next) - op->ar_cb (op->cls, &msg->identity, le->claim); + { + if (le->reference != NULL && le->attest == NULL) + { + for (le2 = attrs->list_head; NULL != le2; le2 = le2->next) + { + if (le2->attest != NULL && le2->attest->id == le->reference->id_attest) + { + op->ar_cb (op->cls, &msg->identity, le->claim, le2->attest, le->reference); + break; + } + + } + } + } GNUNET_RECLAIM_ATTRIBUTE_list_destroy (attrs); attrs = NULL; } - op->ar_cb (op->cls, NULL, NULL); + op->ar_cb (op->cls, NULL, NULL, NULL, NULL); } GNUNET_CONTAINER_DLL_remove (h->op_head, h->op_tail, op); free_op (op); @@ -597,7 +611,7 @@ handle_attribute_result (void *cls, const struct AttributeResultMessage *msg) if (NULL != op) { if (NULL != op->ar_cb) - op->ar_cb (op->cls, NULL, NULL); + op->ar_cb (op->cls, NULL, NULL, NULL, NULL); GNUNET_CONTAINER_DLL_remove (h->op_head, h->op_tail, op); free_op (op); } @@ -610,12 +624,111 @@ handle_attribute_result (void *cls, const struct AttributeResultMessage *msg) if (NULL != it) { if (NULL != it->proc) - it->proc (it->proc_cls, &msg->identity, attr); + it->proc (it->proc_cls, &msg->identity, attr, NULL, NULL); + } + else if (NULL != op) + { + if (NULL != op->ar_cb) + op->ar_cb (op->cls, &msg->identity, attr, NULL, NULL); + } + GNUNET_free (attr); + return; + } + GNUNET_assert (0); +} + +/** + * Handle an incoming message of type + * #GNUNET_MESSAGE_TYPE_RECLAIM_ATTESTATION_RESULT + * + * @param cls + * @param msg the message we received + * @return #GNUNET_OK on success, #GNUNET_SYSERR on error + */ +static int +check_attestation_result (void *cls, const struct AttributeResultMessage *msg) +{ + size_t msg_len; + size_t attr_len; + + msg_len = ntohs (msg->header.size); + attr_len = ntohs (msg->attr_len); + if (msg_len != sizeof(struct AttributeResultMessage) + attr_len) + { + GNUNET_break (0); + return GNUNET_SYSERR; + } + return GNUNET_OK; +} + + +/** + * Handle an incoming message of type + * #GNUNET_MESSAGE_TYPE_RECLAIM_ATTESTATION_RESULT + * + * @param cls + * @param msg the message we received + */ +static void +handle_attestation_result (void *cls, const struct AttributeResultMessage *msg) +{ + static struct GNUNET_CRYPTO_EcdsaPrivateKey identity_dummy; + struct GNUNET_RECLAIM_Handle *h = cls; + struct GNUNET_RECLAIM_AttributeIterator *it; + struct GNUNET_RECLAIM_Operation *op; + size_t attr_len; + uint32_t r_id = ntohl (msg->id); + + attr_len = ntohs (msg->attr_len); + LOG (GNUNET_ERROR_TYPE_DEBUG, "Processing attestation result.\n"); + + + for (it = h->it_head; NULL != it; it = it->next) + if (it->r_id == r_id) + break; + for (op = h->op_head; NULL != op; op = op->next) + if (op->r_id == r_id) + break; + if ((NULL == it) && (NULL == op)) + return; + + if ((0 == + (memcmp (&msg->identity, &identity_dummy, sizeof(identity_dummy))))) + { + if ((NULL == it) && (NULL == op)) + { + GNUNET_break (0); + force_reconnect (h); + return; + } + if (NULL != it) + { + if (NULL != it->finish_cb) + it->finish_cb (it->finish_cb_cls); + free_it (it); + } + if (NULL != op) + { + if (NULL != op->ar_cb) + op->ar_cb (op->cls, NULL, NULL, NULL, NULL); + GNUNET_CONTAINER_DLL_remove (h->op_head, h->op_tail, op); + free_op (op); + } + return; + } + + { + struct GNUNET_RECLAIM_ATTESTATION_Claim *attr; + attr = GNUNET_RECLAIM_ATTESTATION_deserialize ((char *) &msg[1], attr_len); + if (NULL != it) + { + if (NULL != it->proc) + it->proc (it->proc_cls, &msg->identity, NULL, attr, NULL); } else if (NULL != op) { if (NULL != op->ar_cb) - op->ar_cb (op->cls, &msg->identity, attr); + op->ar_cb (op->cls, &msg->identity, NULL, attr, NULL); } GNUNET_free (attr); return; @@ -623,6 +736,110 @@ handle_attribute_result (void *cls, const struct AttributeResultMessage *msg) GNUNET_assert (0); } +/** + * Handle an incoming message of type + * #GNUNET_MESSAGE_TYPE_RECLAIM_REFERENCE_RESULT + * + * @param cls + * @param msg the message we received + * @return #GNUNET_OK on success, #GNUNET_SYSERR on error + */ +static int +check_reference_result (void *cls, const struct ReferenceResultMessage *msg) +{ + size_t msg_len; + size_t attr_len; + size_t ref_len; + + msg_len = ntohs (msg->header.size); + attr_len = ntohs (msg->attest_len); + ref_len = ntohs (msg->ref_len); + if (msg_len != sizeof(struct ReferenceResultMessage) + attr_len + ref_len) + { + GNUNET_break (0); + return GNUNET_SYSERR; + } + return GNUNET_OK; +} + +/** +* Handle an incoming message of type +* #GNUNET_MESSAGE_TYPE_RECLAIM_REFERENCE_RESULT +* +* @param cls +* @param msg the message we received +*/ +static void +handle_reference_result (void *cls, const struct ReferenceResultMessage *msg) +{ + static struct GNUNET_CRYPTO_EcdsaPrivateKey identity_dummy; + struct GNUNET_RECLAIM_Handle *h = cls; + struct GNUNET_RECLAIM_AttributeIterator *it; + struct GNUNET_RECLAIM_Operation *op; + size_t attest_len; + size_t ref_len; + uint32_t r_id = ntohl (msg->id); + attest_len = ntohs (msg->attest_len); + ref_len = ntohs (msg->ref_len); + LOG (GNUNET_ERROR_TYPE_DEBUG, "Processing reference result.\n"); + for (it = h->it_head; NULL != it; it = it->next) + if (it->r_id == r_id) + break; + for (op = h->op_head; NULL != op; op = op->next) + if (op->r_id == r_id) + break; + if ((NULL == it) && (NULL == op)) + return; + + if ((0 == + (memcmp (&msg->identity, &identity_dummy, sizeof(identity_dummy))))) + { + if ((NULL == it) && (NULL == op)) + { + GNUNET_break (0); + force_reconnect (h); + return; + } + if (NULL != it) + { + if (NULL != it->finish_cb) + it->finish_cb (it->finish_cb_cls); + free_it (it); + } + if (NULL != op) + { + if (NULL != op->ar_cb) + op->ar_cb (op->cls, NULL, NULL, NULL, NULL); + GNUNET_CONTAINER_DLL_remove (h->op_head, h->op_tail, op); + free_op (op); + } + return; + } + + { + struct GNUNET_RECLAIM_ATTESTATION_REFERENCE *ref; + struct GNUNET_RECLAIM_ATTESTATION_Claim *attest; + attest = GNUNET_RECLAIM_ATTESTATION_deserialize ((char *) &msg[1], + attest_len); + ref = GNUNET_RECLAIM_ATTESTATION_REF_deserialize ((char *) &msg[1] + + attest_len, + ref_len); + if (NULL != it) + { + if (NULL != it->proc) + it->proc (it->proc_cls, &msg->identity, NULL, attest, ref); + } + else if (NULL != op) + { + if (NULL != op->ar_cb) + op->ar_cb (op->cls, &msg->identity, NULL, attest, ref); + } + GNUNET_free (ref); + GNUNET_free (attest); + return; + } + GNUNET_assert (0); +} /** * Handle an incoming message of type @@ -742,6 +959,14 @@ reconnect (struct GNUNET_RECLAIM_Handle *h) GNUNET_MESSAGE_TYPE_RECLAIM_ATTRIBUTE_RESULT, struct AttributeResultMessage, h), + GNUNET_MQ_hd_var_size (attestation_result, + GNUNET_MESSAGE_TYPE_RECLAIM_ATTESTATION_RESULT, + struct AttributeResultMessage, + h), + GNUNET_MQ_hd_var_size (reference_result, + GNUNET_MESSAGE_TYPE_RECLAIM_REFERENCE_RESULT, + struct ReferenceResultMessage, + h), GNUNET_MQ_hd_fixed_size (ticket_result, GNUNET_MESSAGE_TYPE_RECLAIM_TICKET_RESULT, struct TicketResultMessage, @@ -925,6 +1150,185 @@ GNUNET_RECLAIM_attribute_delete ( return op; } +/** + * Store an attestation. If the attestation is already present, + * it is replaced with the new attestation. + * + * @param h handle to the re:claimID service + * @param pkey private key of the identity + * @param attr the attestation value + * @param exp_interval the relative expiration interval for the attestation + * @param cont continuation to call when done + * @param cont_cls closure for @a cont + * @return handle to abort the request + */ +struct GNUNET_RECLAIM_Operation * +GNUNET_RECLAIM_attestation_store ( + struct GNUNET_RECLAIM_Handle *h, + const struct GNUNET_CRYPTO_EcdsaPrivateKey *pkey, + const struct GNUNET_RECLAIM_ATTESTATION_Claim *attr, + const struct GNUNET_TIME_Relative *exp_interval, + GNUNET_RECLAIM_ContinuationWithStatus cont, + void *cont_cls) +{ + struct GNUNET_RECLAIM_Operation *op; + struct AttributeStoreMessage *sam; + size_t attr_len; + + op = GNUNET_new (struct GNUNET_RECLAIM_Operation); + op->h = h; + op->as_cb = cont; + op->cls = cont_cls; + op->r_id = h->r_id_gen++; + GNUNET_CONTAINER_DLL_insert_tail (h->op_head, h->op_tail, op); + attr_len = GNUNET_RECLAIM_ATTESTATION_serialize_get_size (attr); + op->env = GNUNET_MQ_msg_extra (sam, + attr_len, + GNUNET_MESSAGE_TYPE_RECLAIM_ATTESTATION_STORE); + sam->identity = *pkey; + sam->id = htonl (op->r_id); + sam->exp = GNUNET_htonll (exp_interval->rel_value_us); + + GNUNET_RECLAIM_ATTESTATION_serialize (attr, (char *) &sam[1]); + + sam->attr_len = htons (attr_len); + if (NULL != h->mq) + GNUNET_MQ_send_copy (h->mq, op->env); + return op; +} + +/** + * Delete an attestation. Tickets used to share this attestation are updated + * accordingly. + * + * @param h handle to the re:claimID service + * @param pkey Private key of the identity to add an attribute to + * @param attr The attestation + * @param cont Continuation to call when done + * @param cont_cls Closure for @a cont + * @return handle Used to to abort the request + */ +struct GNUNET_RECLAIM_Operation * +GNUNET_RECLAIM_attestation_delete ( + struct GNUNET_RECLAIM_Handle *h, + const struct GNUNET_CRYPTO_EcdsaPrivateKey *pkey, + const struct GNUNET_RECLAIM_ATTESTATION_Claim *attr, + GNUNET_RECLAIM_ContinuationWithStatus cont, + void *cont_cls) +{ + struct GNUNET_RECLAIM_Operation *op; + struct AttributeDeleteMessage *dam; + size_t attr_len; + + op = GNUNET_new (struct GNUNET_RECLAIM_Operation); + op->h = h; + op->as_cb = cont; + op->cls = cont_cls; + op->r_id = h->r_id_gen++; + GNUNET_CONTAINER_DLL_insert_tail (h->op_head, h->op_tail, op); + attr_len = GNUNET_RECLAIM_ATTESTATION_serialize_get_size (attr); + op->env = GNUNET_MQ_msg_extra (dam, + attr_len, + GNUNET_MESSAGE_TYPE_RECLAIM_ATTESTATION_DELETE); + dam->identity = *pkey; + dam->id = htonl (op->r_id); + GNUNET_RECLAIM_ATTESTATION_serialize (attr, (char *) &dam[1]); + + dam->attr_len = htons (attr_len); + if (NULL != h->mq) + GNUNET_MQ_send_copy (h->mq, op->env); + return op; +} + +/** + * Store an attestation reference. If the reference is already present, + * it is replaced with the new reference. + * + * @param h handle to the re:claimID service + * @param pkey private key of the identity + * @param attr the reference value + * @param exp_interval the relative expiration interval for the reference + * @param cont continuation to call when done + * @param cont_cls closure for @a cont + * @return handle to abort the request + */ +struct GNUNET_RECLAIM_Operation * +GNUNET_RECLAIM_attestation_reference_store ( + struct GNUNET_RECLAIM_Handle *h, + const struct GNUNET_CRYPTO_EcdsaPrivateKey *pkey, + const struct GNUNET_RECLAIM_ATTESTATION_REFERENCE *attr, + const struct GNUNET_TIME_Relative *exp_interval, + GNUNET_RECLAIM_ContinuationWithStatus cont, + void *cont_cls) +{ + struct GNUNET_RECLAIM_Operation *op; + struct AttributeStoreMessage *sam; + size_t attr_len; + op = GNUNET_new (struct GNUNET_RECLAIM_Operation); + op->h = h; + op->as_cb = cont; + op->cls = cont_cls; + op->r_id = h->r_id_gen++; + GNUNET_CONTAINER_DLL_insert_tail (h->op_head, h->op_tail, op); + attr_len = GNUNET_RECLAIM_ATTESTATION_REF_serialize_get_size (attr); + op->env = GNUNET_MQ_msg_extra (sam, + attr_len, + GNUNET_MESSAGE_TYPE_RECLAIM_REFERENCE_STORE); + sam->identity = *pkey; + sam->id = htonl (op->r_id); + sam->exp = GNUNET_htonll (exp_interval->rel_value_us); + + GNUNET_RECLAIM_ATTESTATION_REF_serialize (attr, (char *) &sam[1]); + + sam->attr_len = htons (attr_len); + if (NULL != h->mq) + GNUNET_MQ_send_copy (h->mq, op->env); + return op; +} + +/** + * Delete an attestation reference. Tickets used to share this reference are updated + * accordingly. + * + * @param h handle to the re:claimID service + * @param pkey Private key of the identity to delete the reference from + * @param attr The reference + * @param cont Continuation to call when done + * @param cont_cls Closure for @a cont + * @return handle Used to to abort the request + */ +struct GNUNET_RECLAIM_Operation * +GNUNET_RECLAIM_attestation_reference_delete ( + struct GNUNET_RECLAIM_Handle *h, + const struct GNUNET_CRYPTO_EcdsaPrivateKey *pkey, + const struct GNUNET_RECLAIM_ATTESTATION_REFERENCE *attr, + GNUNET_RECLAIM_ContinuationWithStatus cont, + void *cont_cls) +{ + + struct GNUNET_RECLAIM_Operation *op; + struct AttributeDeleteMessage *dam; + size_t attr_len; + + op = GNUNET_new (struct GNUNET_RECLAIM_Operation); + op->h = h; + op->as_cb = cont; + op->cls = cont_cls; + op->r_id = h->r_id_gen++; + GNUNET_CONTAINER_DLL_insert_tail (h->op_head, h->op_tail, op); + attr_len = GNUNET_RECLAIM_ATTESTATION_REF_serialize_get_size (attr); + op->env = GNUNET_MQ_msg_extra (dam, + attr_len, + GNUNET_MESSAGE_TYPE_RECLAIM_REFERENCE_DELETE); + dam->identity = *pkey; + dam->id = htonl (op->r_id); + GNUNET_RECLAIM_ATTESTATION_REF_serialize (attr, (char *) &dam[1]); + + dam->attr_len = htons (attr_len); + if (NULL != h->mq) + GNUNET_MQ_send_copy (h->mq, op->env); + return op; +} /** * List all attributes for a local identity. diff --git a/src/transport/Makefile.am b/src/transport/Makefile.am index c37a34ab7..077c0409a 100644 --- a/src/transport/Makefile.am +++ b/src/transport/Makefile.am @@ -1527,15 +1527,15 @@ test_transport_api_slow_ats_peer2.conf \ tcp_server_mst_legacy.c \ tcp_server_legacy.c \ tcp_service_legacy.c \ -test_communicator_basic_unix_peer1.conf \ -test_communicator_basic_unix_peer2.conf \ -test_communicator_basic_tcp_peer1.conf \ -test_communicator_basic_tcp_peer2.conf \ -test_communicator_basic_udp_peer1.conf \ -test_communicator_basic_udp_peer2.conf \ -test_communicator_rekey_tcp_peer1.conf \ -test_communicator_rekey_tcp_peer2.conf \ -test_communicator_rekey_udp_peer1.conf \ -test_communicator_rekey_udp_peer2.conf \ -test_communicator_backchannel_udp_peer1.conf \ -test_communicator_backchannel_udp_peer2.conf +test_communicator_unix_basic_peer1.conf \ +test_communicator_unix_basic_peer2.conf \ +test_communicator_tcp_basic_peer1.conf \ +test_communicator_tcp_basic_peer2.conf \ +test_communicator_udp_basic_peer1.conf \ +test_communicator_udp_basic_peer2.conf \ +test_communicator_tcp_rekey_peer1.conf \ +test_communicator_tcp_rekey_peer2.conf \ +test_communicator_udp_rekey_peer1.conf \ +test_communicator_udp_rekey_peer2.conf \ +test_communicator_udp_backchannel_peer1.conf \ +test_communicator_udp_backchannel_peer2.conf diff --git a/src/transport/test_communicator_unix_peer1.conf b/src/transport/test_communicator_unix_basic_peer1.conf index d50588007..d50588007 100644 --- a/src/transport/test_communicator_unix_peer1.conf +++ b/src/transport/test_communicator_unix_basic_peer1.conf diff --git a/src/util/.gitignore b/src/util/.gitignore index 01ebcc834..84c13708e 100644 --- a/src/util/.gitignore +++ b/src/util/.gitignore @@ -1,6 +1,7 @@ test_common_logging_dummy gnunet-config gnunet-config-diff +gnunet-crypto-tvg gnunet-ecc gnunet-qr gnunet-resolver @@ -30,6 +31,7 @@ test_container_multihashmap32 test_container_multipeermap test_crypto_crc test_crypto_ecc_dlog +test_crypto_ecdh_ecdsa test_crypto_ecdh_eddsa test_crypto_ecdhe test_crypto_ecdsa diff --git a/src/util/Makefile.am b/src/util/Makefile.am index 0f6251f96..fc8f424dc 100644 --- a/src/util/Makefile.am +++ b/src/util/Makefile.am @@ -39,6 +39,7 @@ libgnunetutil_la_SOURCES = \ bandwidth.c \ $(BENCHMARK) \ bio.c \ + buffer.c \ client.c \ common_allocation.c \ common_endian.c \ @@ -138,41 +139,11 @@ libgnunetutil_la_LDFLAGS = \ $(GN_LIB_LDFLAGS) \ -version-info 13:2:0 -libgnunetutil_taler_wallet_la_SOURCES = \ - common_allocation.c \ - common_endian.c \ - common_logging.c \ - container_heap.c \ - container_multihashmap.c \ - container_multihashmap32.c \ - crypto_symmetric.c \ - crypto_crc.c \ - crypto_ecc.c \ - crypto_hash.c \ - crypto_hkdf.c \ - crypto_kdf.c \ - crypto_mpi.c \ - crypto_random.c \ - crypto_rsa.c \ - strings.c \ - time.c - -libgnunetutil_taler_wallet_la_LIBADD = \ - $(LIBGCRYPT_LIBS) \ - -lunistring - -libgnunetutil_taler_wallet_la_LDFLAGS = \ - $(GN_LIB_LDFLAGS) \ - -version-info 0:0:0 - if HAVE_TESTING GNUNET_ECC = gnunet-ecc GNUNET_SCRYPT = gnunet-scrypt endif -if TALER_ONLY -lib_LTLIBRARIES = libgnunetutil_taler_wallet.la -else lib_LTLIBRARIES = libgnunetutil.la libexec_PROGRAMS = \ @@ -182,6 +153,7 @@ libexec_PROGRAMS = \ bin_PROGRAMS = \ gnunet-resolver \ gnunet-config \ + gnunet-crypto-tvg \ $(GNUNET_ECC) \ $(GNUNET_SCRYPT) \ gnunet-uri @@ -199,8 +171,6 @@ AM_TESTS_ENVIRONMENT=export GNUNET_PREFIX=$${GNUNET_PREFIX:-@libdir@};export PAT TESTS = $(check_PROGRAMS) endif -endif - gnunet_timeout_SOURCES = \ gnunet-timeout.c @@ -220,6 +190,11 @@ gnunet_resolver_LDADD = \ libgnunetutil.la \ $(GN_LIBINTL) +gnunet_crypto_tvg_SOURCES = \ + gnunet-crypto-tvg.c +gnunet_crypto_tvg_LDADD = \ + libgnunetutil.la \ + $(GN_LIBINTL) -lgcrypt gnunet_ecc_SOURCES = \ gnunet-ecc.c @@ -298,6 +273,7 @@ check_PROGRAMS = \ test_crypto_eddsa \ test_crypto_ecdhe \ test_crypto_ecdh_eddsa \ + test_crypto_ecdh_ecdsa \ test_crypto_ecc_dlog \ test_crypto_hash \ test_crypto_hash_context \ @@ -476,6 +452,13 @@ test_crypto_ecdh_eddsa_LDADD = \ libgnunetutil.la \ $(LIBGCRYPT_LIBS) +test_crypto_ecdh_ecdsa_SOURCES = \ + test_crypto_ecdh_ecdsa.c +test_crypto_ecdh_ecdsa_LDADD = \ + libgnunetutil.la \ + $(LIBGCRYPT_LIBS) + + test_crypto_hash_SOURCES = \ test_crypto_hash.c test_crypto_hash_LDADD = \ diff --git a/src/util/buffer.c b/src/util/buffer.c new file mode 100644 index 000000000..d89565d68 --- /dev/null +++ b/src/util/buffer.c @@ -0,0 +1,226 @@ +/* + This file is part of GNUnet + Copyright (C) 2020 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, 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 + GNUnet; see the file COPYING. If not, see <http://www.gnu.org/licenses/> +*/ +/** + * @file buffer.c + * @brief Common buffer management functions. + * @author Florian Dold + */ +#include "platform.h" +#include "gnunet_util_lib.h" +#include "gnunet_buffer_lib.h" + +/** + * Initialize a buffer with the given capacity. + * + * When a buffer is allocated with this function, a warning is logged + * when the buffer exceeds the initial capacity. + * + * @param buf the buffer to initialize + * @param capacity the capacity (in bytes) to allocate for @a buf + */ +void +GNUNET_buffer_prealloc (struct GNUNET_Buffer *buf, size_t capacity) +{ + /* Buffer should be zero-initialized */ + GNUNET_assert (0 == buf->mem); + GNUNET_assert (0 == buf->capacity); + GNUNET_assert (0 == buf->position); + buf->mem = GNUNET_malloc (capacity); + buf->capacity = capacity; + buf->warn_grow = GNUNET_YES; +} + + +/** + * Make sure that at least @a n bytes remaining in the buffer. + * + * @param buf buffer to potentially grow + * @param n number of bytes that should be available to write + */ +void +GNUNET_buffer_ensure_remaining (struct GNUNET_Buffer *buf, size_t n) +{ + size_t new_capacity = buf->position + n; + + if (new_capacity <= buf->capacity) + return; + /* warn if calculation of expected size was wrong */ + GNUNET_break (GNUNET_YES != buf->warn_grow); + if (new_capacity < buf->capacity * 2) + new_capacity = buf->capacity * 2; + buf->capacity = new_capacity; + if (NULL != buf->mem) + buf->mem = GNUNET_realloc (buf->mem, new_capacity); + else + buf->mem = GNUNET_malloc (new_capacity); +} + + +/** + * Write bytes to the buffer. + * + * Grows the buffer if necessary. + * + * @param buf buffer to write to + * @param data data to read from + * @param len number of bytes to copy from @a data to @a buf + * + */ +void +GNUNET_buffer_write (struct GNUNET_Buffer *buf, const char *data, size_t len) +{ + GNUNET_buffer_ensure_remaining (buf, len); + memcpy (buf->mem + buf->position, data, len); + buf->position += len; +} + + +/** + * Write a 0-terminated string to a buffer, excluding the 0-terminator. + * + * @param buf the buffer to write to + * @param str the string to write to @a buf + */ +void +GNUNET_buffer_write_str (struct GNUNET_Buffer *buf, const char *str) +{ + size_t len = strlen (str); + + GNUNET_buffer_write (buf, str, len); +} + + +/** + * Clear the buffer and return the string it contained. + * The caller is responsible to eventually #GNUNET_free + * the returned string. + * + * The returned string is always 0-terminated. + * + * @param buf the buffer to reap the string from + * @returns the buffer contained in the string + */ +char * +GNUNET_buffer_reap_str (struct GNUNET_Buffer *buf) +{ + char *res; + + /* ensure 0-termination */ + if ( (0 == buf->position) || ('\0' != buf->mem[buf->position - 1])) + { + GNUNET_buffer_ensure_remaining (buf, 1); + buf->mem[buf->position++] = '\0'; + } + res = buf->mem; + *buf = (struct GNUNET_Buffer) { 0 }; + return res; +} + + +/** + * Free the backing memory of the given buffer. + * Does not free the memory of the buffer control structure, + * which is typically stack-allocated. + */ +void +GNUNET_buffer_clear (struct GNUNET_Buffer *buf) +{ + GNUNET_free_non_null (buf->mem); + *buf = (struct GNUNET_Buffer) { 0 }; +} + + +/** + * Write a path component to a buffer, ensuring that + * there is exactly one slash between the previous contents + * of the buffer and the new string. + * + * @param buf buffer to write to + * @param str string containing the new path component + */ +void +GNUNET_buffer_write_path (struct GNUNET_Buffer *buf, const char *str) +{ + size_t len = strlen (str); + + while ( (0 != len) && ('/' == str[0]) ) + { + str++; + len--; + } + if ( (0 == buf->position) || ('/' != buf->mem[buf->position - 1]) ) + { + GNUNET_buffer_ensure_remaining (buf, 1); + buf->mem[buf->position++] = '/'; + } + GNUNET_buffer_write (buf, str, len); +} + + +/** + * Write a 0-terminated formatted string to a buffer, excluding the + * 0-terminator. + * + * Grows the buffer if necessary. + * + * @param buf the buffer to write to + * @param fmt format string + * @param ... format arguments + */ +void +GNUNET_buffer_write_fstr (struct GNUNET_Buffer *buf, const char *fmt, ...) +{ + va_list args; + + va_start (args, fmt); + GNUNET_buffer_write_vfstr (buf, fmt, args); + va_end (args); +} + + +/** + * Write a 0-terminated formatted string to a buffer, excluding the + * 0-terminator. + * + * Grows the buffer if necessary. + * + * @param buf the buffer to write to + * @param fmt format string + * @param args format argument list + */ +void +GNUNET_buffer_write_vfstr (struct GNUNET_Buffer *buf, + const char *fmt, + va_list args) +{ + int res; + va_list args2; + + va_copy (args2, args); + res = vsnprintf (NULL, 0, fmt, args2); + va_end (args2); + + GNUNET_assert (res >= 0); + GNUNET_buffer_ensure_remaining (buf, res + 1); + + va_copy (args2, args); + res = vsnprintf (buf->mem + buf->position, res + 1, fmt, args2); + va_end (args2); + + GNUNET_assert (res >= 0); + buf->position += res; + GNUNET_assert (buf->position <= buf->capacity); +} diff --git a/src/util/common_logging.c b/src/util/common_logging.c index 430f75e70..27ac88a05 100644 --- a/src/util/common_logging.c +++ b/src/util/common_logging.c @@ -294,7 +294,6 @@ resize_logdefs () } -#if ! TALER_WALLET_ONLY /** * Rotate logs, deleting the oldest log. * @@ -403,9 +402,6 @@ setup_log_file (const struct tm *tm) } -#endif - - /** * Utility function - adds a parsed definition to logdefs array. * @@ -731,7 +727,7 @@ GNUNET_log_setup (const char *comp, const char *loglevel, const char *logfile) log_file_name = GNUNET_STRINGS_filename_expand (logfile); if (NULL == log_file_name) return GNUNET_SYSERR; -#if TALER_WALLET_ONLY || defined(GNUNET_CULL_LOGGING) +#if defined(GNUNET_CULL_LOGGING) /* log file option not allowed for wallet logic */ GNUNET_assert (NULL == logfile); return GNUNET_OK; @@ -1023,7 +1019,7 @@ mylog (enum GNUNET_ErrorType kind, } vsnprintf (buf, size, message, va); -#if ! (defined(GNUNET_CULL_LOGGING) || TALER_WALLET_ONLY) +#if ! defined(GNUNET_CULL_LOGGING) if (NULL != tmptr) (void) setup_log_file (tmptr); #endif diff --git a/src/util/crypto_ecc.c b/src/util/crypto_ecc.c index bd7c425d4..237062eb7 100644 --- a/src/util/crypto_ecc.c +++ b/src/util/crypto_ecc.c @@ -173,22 +173,8 @@ GNUNET_CRYPTO_ecdsa_key_get_public ( const struct GNUNET_CRYPTO_EcdsaPrivateKey *priv, struct GNUNET_CRYPTO_EcdsaPublicKey *pub) { - gcry_sexp_t sexp; - gcry_ctx_t ctx; - gcry_mpi_t q; - BENCHMARK_START (ecdsa_key_get_public); - - sexp = decode_private_ecdsa_key (priv); - GNUNET_assert (NULL != sexp); - GNUNET_assert (0 == gcry_mpi_ec_new (&ctx, sexp, NULL)); - gcry_sexp_release (sexp); - q = gcry_mpi_ec_get_mpi ("q@eddsa", ctx, 0); - GNUNET_assert (NULL != q); - GNUNET_CRYPTO_mpi_print_unsigned (pub->q_y, sizeof(pub->q_y), q); - gcry_mpi_release (q); - gcry_ctx_release (ctx); - + GNUNET_TWEETNACL_scalarmult_gnunet_ecdsa (pub->q_y, priv->d); BENCHMARK_END (ecdsa_key_get_public); } @@ -1041,45 +1027,6 @@ GNUNET_CRYPTO_ecdsa_public_key_derive ( /** - * Take point from ECDH and convert it to key material. - * - * @param result point from ECDH - * @param ctx ECC context - * @param key_material[out] set to derived key material - * @return #GNUNET_OK on success - */ -static int -point_to_hash (gcry_mpi_point_t result, - gcry_ctx_t ctx, - struct GNUNET_HashCode *key_material) -{ - gcry_mpi_t result_x; - unsigned char xbuf[256 / 8]; - size_t rsize; - - /* finally, convert point to string for hashing */ - result_x = gcry_mpi_new (256); - if (gcry_mpi_ec_get_affine (result_x, NULL, result, ctx)) - { - LOG_GCRY (GNUNET_ERROR_TYPE_ERROR, "get_affine failed", 0); - return GNUNET_SYSERR; - } - - rsize = sizeof(xbuf); - GNUNET_assert (! gcry_mpi_get_flag (result_x, GCRYMPI_FLAG_OPAQUE)); - /* result_x can be negative here, so we do not use 'GNUNET_CRYPTO_mpi_print_unsigned' - as that does not include the sign bit; x should be a 255-bit - value, so with the sign it should fit snugly into the 256-bit - xbuf */ - GNUNET_assert ( - 0 == gcry_mpi_print (GCRYMPI_FMT_STD, xbuf, rsize, &rsize, result_x)); - GNUNET_CRYPTO_hash (xbuf, rsize, key_material); - gcry_mpi_release (result_x); - return GNUNET_OK; -} - - -/** * @ingroup crypto * Derive key material from a ECDH public key and a private EdDSA key. * Dual to #GNUNET_CRRYPTO_ecdh_eddsa. @@ -1125,41 +1072,18 @@ GNUNET_CRYPTO_ecdsa_ecdh (const struct GNUNET_CRYPTO_EcdsaPrivateKey *priv, const struct GNUNET_CRYPTO_EcdhePublicKey *pub, struct GNUNET_HashCode *key_material) { - gcry_mpi_point_t result; - gcry_mpi_point_t q; - gcry_mpi_t d; - gcry_ctx_t ctx; - gcry_sexp_t pub_sexpr; - int ret; + uint8_t p[GNUNET_TWEETNACL_SCALARMULT_BYTES]; + uint8_t d_rev[GNUNET_TWEETNACL_SCALARMULT_BYTES]; BENCHMARK_START (ecdsa_ecdh); - - /* first, extract the q = dP value from the public key */ - if (0 != gcry_sexp_build (&pub_sexpr, - NULL, - "(public-key(ecc(curve " CURVE ")(q %b)))", - (int) sizeof(pub->q_y), - pub->q_y)) - return GNUNET_SYSERR; - GNUNET_assert (0 == gcry_mpi_ec_new (&ctx, pub_sexpr, NULL)); - gcry_sexp_release (pub_sexpr); - q = gcry_mpi_ec_get_point ("q", ctx, 0); - - /* second, extract the d value from our private key */ - GNUNET_CRYPTO_mpi_scan_unsigned (&d, priv->d, sizeof(priv->d)); - - /* then call the 'multiply' function, to compute the product */ - result = gcry_mpi_point_new (0); - gcry_mpi_ec_mul (result, d, q, ctx); - gcry_mpi_point_release (q); - gcry_mpi_release (d); - - /* finally, convert point to string for hashing */ - ret = point_to_hash (result, ctx, key_material); - gcry_mpi_point_release (result); - gcry_ctx_release (ctx); + for (size_t i = 0; i < 32; i++) + d_rev[i] = priv->d[31 - i]; + GNUNET_TWEETNACL_scalarmult_curve25519 (p, d_rev, pub->q_y); + GNUNET_CRYPTO_hash (p, + GNUNET_TWEETNACL_SCALARMULT_BYTES, + key_material); BENCHMARK_END (ecdsa_ecdh); - return ret; + return GNUNET_OK; } @@ -1191,7 +1115,7 @@ GNUNET_CRYPTO_ecdh_eddsa (const struct GNUNET_CRYPTO_EcdhePrivateKey *priv, /** * @ingroup crypto * Derive key material from a ECDSA public key and a private ECDH key. - * Dual to #GNUNET_CRRYPTO_eddsa_ecdh. + * Dual to #GNUNET_CRYPTO_ecdsa_ecdh. * * @param priv private key to use for the ECDH (y) * @param pub public key from ECDSA to use for the ECDH (X=h(x)G) @@ -1203,10 +1127,13 @@ GNUNET_CRYPTO_ecdh_ecdsa (const struct GNUNET_CRYPTO_EcdhePrivateKey *priv, const struct GNUNET_CRYPTO_EcdsaPublicKey *pub, struct GNUNET_HashCode *key_material) { - return GNUNET_CRYPTO_ecdh_eddsa (priv, - (const struct GNUNET_CRYPTO_EddsaPublicKey *) - pub, - key_material); + uint8_t p[GNUNET_TWEETNACL_SCALARMULT_BYTES]; + uint8_t curve25510_pk[GNUNET_TWEETNACL_SIGN_PUBLICBYTES]; + + GNUNET_TWEETNACL_sign_ed25519_pk_to_curve25519 (curve25510_pk, pub->q_y); + GNUNET_TWEETNACL_scalarmult_curve25519 (p, priv->d, curve25510_pk); + GNUNET_CRYPTO_hash (p, GNUNET_TWEETNACL_SCALARMULT_BYTES, key_material); + return GNUNET_OK; } diff --git a/src/util/gnunet-crypto-tvg.c b/src/util/gnunet-crypto-tvg.c new file mode 100644 index 000000000..7d151c10b --- /dev/null +++ b/src/util/gnunet-crypto-tvg.c @@ -0,0 +1,278 @@ +/* + This file is part of GNUnet. + Copyright (C) 2020 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 <http://www.gnu.org/licenses/>. + + SPDX-License-Identifier: AGPL3.0-or-later + */ + +/** + * @file util/gnunet-crypto-tgv.c + * @brief Generate test vectors for cryptographic operations. + * @author Florian Dold + */ +#include "platform.h" +#include "gnunet_util_lib.h" +#include "gnunet_signatures.h" +#include "gnunet_testing_lib.h" +#include <gcrypt.h> + +GNUNET_NETWORK_STRUCT_BEGIN + +/** + * Sample signature struct. + * + * Purpose is #GNUNET_SIGNATURE_PURPOSE_TEST + */ +struct TestSignatureDataPS +{ + struct GNUNET_CRYPTO_EccSignaturePurpose purpose; + uint32_t testval; +}; + +GNUNET_NETWORK_STRUCT_END + + +/** + * Print data base32-crockford with a preceding label. + * + * @param label label to print + * @param data data to print + * @param size size of data + */ +static void +display_data (char *label, void *data, size_t size) +{ + char *enc = GNUNET_STRINGS_data_to_string_alloc (data, size); + printf ("%s %s\n", label, enc); + GNUNET_free (enc); +} + + +/** + * 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 cfg configuration + */ +static void +run (void *cls, + char *const *args, + const char *cfgfile, + const struct GNUNET_CONFIGURATION_Handle *cfg) +{ + { + struct GNUNET_HashCode hc; + char *str = "Hello, GNUnet"; + + GNUNET_CRYPTO_hash (str, strlen (str), &hc); + + printf ("hash code:\n"); + display_data (" input", str, strlen (str)); + display_data (" output", &hc, sizeof (struct GNUNET_HashCode)); + } + { + struct GNUNET_CRYPTO_EcdhePrivateKey *priv1; + struct GNUNET_CRYPTO_EcdhePublicKey pub1; + struct GNUNET_CRYPTO_EcdhePrivateKey *priv2; + struct GNUNET_HashCode skm; + priv1 = GNUNET_CRYPTO_ecdhe_key_create (); + priv2 = GNUNET_CRYPTO_ecdhe_key_create (); + GNUNET_CRYPTO_ecdhe_key_get_public (priv1, &pub1); + GNUNET_assert (GNUNET_OK == GNUNET_CRYPTO_ecc_ecdh (priv2, &pub1, &skm)); + + printf ("ecdhe key:\n"); + display_data (" priv1", priv1, sizeof (struct + GNUNET_CRYPTO_EcdhePrivateKey)); + display_data (" pub1", &pub1, sizeof (struct + GNUNET_CRYPTO_EcdhePublicKey)); + display_data (" priv2", priv2, sizeof (struct + GNUNET_CRYPTO_EcdhePrivateKey)); + display_data (" skm", &skm, sizeof (struct GNUNET_HashCode)); + GNUNET_free (priv1); + GNUNET_free (priv2); + } + + { + struct GNUNET_CRYPTO_EddsaPrivateKey *priv; + struct GNUNET_CRYPTO_EddsaPublicKey pub; + priv = GNUNET_CRYPTO_eddsa_key_create (); + GNUNET_CRYPTO_eddsa_key_get_public (priv, &pub); + + printf ("eddsa key:\n"); + display_data (" priv", priv, sizeof (struct + GNUNET_CRYPTO_EddsaPrivateKey)); + display_data (" pub", &pub, sizeof (struct GNUNET_CRYPTO_EddsaPublicKey)); + GNUNET_free (priv); + } + { + struct GNUNET_CRYPTO_EddsaPrivateKey *priv; + struct GNUNET_CRYPTO_EddsaPublicKey pub; + struct GNUNET_CRYPTO_EddsaSignature sig; + struct TestSignatureDataPS data = { 0 }; + priv = GNUNET_CRYPTO_eddsa_key_create (); + GNUNET_CRYPTO_eddsa_key_get_public (priv, &pub); + data.purpose.size = htonl (sizeof (struct TestSignatureDataPS)); + data.purpose.size = htonl (GNUNET_SIGNATURE_PURPOSE_TEST); + GNUNET_assert (GNUNET_OK == GNUNET_CRYPTO_eddsa_sign (priv, &data.purpose, + &sig)); + GNUNET_assert (GNUNET_OK == GNUNET_CRYPTO_eddsa_verify (0, + &data.purpose, + &sig, + &pub)); + + printf ("eddsa sig:\n"); + display_data (" priv", priv, sizeof (struct + GNUNET_CRYPTO_EddsaPrivateKey)); + display_data (" pub", &pub, sizeof (struct GNUNET_CRYPTO_EddsaPublicKey)); + display_data (" data", &data, sizeof (struct TestSignatureDataPS)); + display_data (" sig", &sig, sizeof (struct GNUNET_CRYPTO_EddsaSignature)); + GNUNET_free (priv); + } + + { + size_t out_len = 64; + char out[out_len]; + char *ikm = "I'm the secret input key material"; + char *salt = "I'm very salty"; + char *ctx = "I'm a context chunk, also known as 'info' in the RFC"; + + GNUNET_assert (GNUNET_OK == GNUNET_CRYPTO_kdf (&out, + out_len, + salt, + strlen (salt), + ikm, + strlen (ikm), + ctx, + strlen (ctx), + NULL)); + + printf ("kdf:\n"); + display_data (" salt", salt, strlen (salt)); + display_data (" ikm", ikm, strlen (ikm)); + display_data (" ctx", ctx, strlen (ctx)); + printf (" out_len %u\n", (unsigned int) out_len); + display_data (" out", out, out_len); + } + { + struct GNUNET_CRYPTO_EcdhePrivateKey *priv_ecdhe; + struct GNUNET_CRYPTO_EcdhePublicKey pub_ecdhe; + struct GNUNET_CRYPTO_EddsaPrivateKey *priv_eddsa; + struct GNUNET_CRYPTO_EddsaPublicKey pub_eddsa; + struct GNUNET_HashCode key_material; + priv_ecdhe = GNUNET_CRYPTO_ecdhe_key_create (); + GNUNET_CRYPTO_ecdhe_key_get_public (priv_ecdhe, &pub_ecdhe); + priv_eddsa = GNUNET_CRYPTO_eddsa_key_create (); + GNUNET_CRYPTO_eddsa_key_get_public (priv_eddsa, &pub_eddsa); + GNUNET_CRYPTO_ecdh_eddsa (priv_ecdhe, &pub_eddsa, &key_material); + + printf ("eddsa_ecdh:\n"); + display_data (" priv_ecdhe", priv_ecdhe, sizeof (struct + GNUNET_CRYPTO_EcdhePrivateKey)); + display_data (" pub_ecdhe", &pub_ecdhe, sizeof (struct + GNUNET_CRYPTO_EcdhePublicKey)); + display_data (" priv_eddsa", priv_eddsa, sizeof (struct + GNUNET_CRYPTO_EddsaPrivateKey)); + display_data (" pub_eddsa", &pub_eddsa, sizeof (struct + GNUNET_CRYPTO_EddsaPublicKey)); + display_data (" key_material", &key_material, sizeof (struct + GNUNET_HashCode)); + } + + { + struct GNUNET_CRYPTO_RsaPrivateKey *skey; + struct GNUNET_CRYPTO_RsaPublicKey *pkey; + struct GNUNET_HashCode message_hash; + struct GNUNET_CRYPTO_RsaBlindingKeySecret bks; + struct GNUNET_CRYPTO_RsaSignature *blinded_sig; + struct GNUNET_CRYPTO_RsaSignature *sig; + char *blinded_data; + size_t blinded_len; + char *public_enc_data; + size_t public_enc_len; + char *blinded_sig_enc_data; + size_t blinded_sig_enc_length; + char *sig_enc_data; + size_t sig_enc_length; + skey = GNUNET_CRYPTO_rsa_private_key_create (2048); + pkey = GNUNET_CRYPTO_rsa_private_key_get_public (skey); + GNUNET_CRYPTO_random_block (GNUNET_CRYPTO_QUALITY_WEAK, &message_hash, + sizeof (struct GNUNET_HashCode)); + GNUNET_CRYPTO_random_block (GNUNET_CRYPTO_QUALITY_WEAK, &bks, sizeof (struct + GNUNET_CRYPTO_RsaBlindingKeySecret)); + GNUNET_assert (GNUNET_YES == GNUNET_CRYPTO_rsa_blind (&message_hash, &bks, + pkey, &blinded_data, + &blinded_len)); + blinded_sig = GNUNET_CRYPTO_rsa_sign_blinded (skey, blinded_data, + blinded_len); + sig = GNUNET_CRYPTO_rsa_unblind (blinded_sig, &bks, pkey); + GNUNET_assert (GNUNET_YES == GNUNET_CRYPTO_rsa_verify (&message_hash, sig, + pkey)); + public_enc_len = GNUNET_CRYPTO_rsa_public_key_encode (pkey, + &public_enc_data); + blinded_sig_enc_length = GNUNET_CRYPTO_rsa_signature_encode (blinded_sig, + & + blinded_sig_enc_data); + sig_enc_length = GNUNET_CRYPTO_rsa_signature_encode (sig, &sig_enc_data); + printf ("blind signing:\n"); + display_data (" message_hash", &message_hash, sizeof (struct + GNUNET_HashCode)); + display_data (" rsa_public_key", public_enc_data, public_enc_len); + display_data (" blinding_key_secret", &bks, sizeof (struct + GNUNET_CRYPTO_RsaBlindingKeySecret)); + display_data (" blinded_message", blinded_data, blinded_len); + display_data (" blinded_sig", blinded_sig_enc_data, + blinded_sig_enc_length); + display_data (" sig", sig_enc_data, sig_enc_length); + GNUNET_CRYPTO_rsa_private_key_free (skey); + GNUNET_CRYPTO_rsa_public_key_free (pkey); + GNUNET_CRYPTO_rsa_signature_free (sig); + GNUNET_CRYPTO_rsa_signature_free (blinded_sig); + } +} + + +/** + * The main function of the test vector generation tool. + * + * @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) +{ + const struct GNUNET_GETOPT_CommandLineOption options[] = { + GNUNET_GETOPT_OPTION_END + }; + + GNUNET_assert (GNUNET_OK == + GNUNET_log_setup ("gnunet-crypto-tvg", + "INFO", + NULL)); + if (GNUNET_OK != + GNUNET_PROGRAM_run (argc, argv, + "gnunet-crypto-tvg", + "Generate test vectors for cryptographic operations", + options, + &run, NULL)) + return 1; + return 0; +} + +/* end of gnunet-crypto-tvg.c */ diff --git a/src/util/test_crypto_ecdh_ecdsa.c b/src/util/test_crypto_ecdh_ecdsa.c new file mode 100644 index 000000000..8a581ef73 --- /dev/null +++ b/src/util/test_crypto_ecdh_ecdsa.c @@ -0,0 +1,97 @@ +/* + This file is part of GNUnet. + Copyright (C) 2002-2015 GNUnet e.V. + + GNUnet is free software: you can redistribute it and/or modify it + under the terms of the GNU Affero General Public License as published + by the Free Software Foundation, either version 3 of the License, + or (at your option) any later version. + + GNUnet is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Affero General Public License for more details. + + You should have received a copy of the GNU Affero General Public License + along with this program. If not, see <http://www.gnu.org/licenses/>. + + SPDX-License-Identifier: AGPL3.0-or-later + + */ +/** + * @file util/test_crypto_ecdh_ecdsa.c + * @brief testcase for ECC DH key exchange with ECDSA private keys. + * @author Christian Grothoff + * @author Bart Polot + */ +#include "platform.h" +#include "gnunet_util_lib.h" +#include <gcrypt.h> + + +static int +test_ecdh () +{ + struct GNUNET_CRYPTO_EcdsaPrivateKey *priv_dsa; + struct GNUNET_CRYPTO_EcdhePrivateKey *priv_ecdh; + struct GNUNET_CRYPTO_EcdsaPublicKey id1; + struct GNUNET_CRYPTO_EcdhePublicKey id2; + struct GNUNET_HashCode dh[2]; + + /* Generate keys */ + priv_dsa = GNUNET_CRYPTO_ecdsa_key_create (); + GNUNET_CRYPTO_ecdsa_key_get_public (priv_dsa, + &id1); + for (unsigned int j = 0; j < 4; j++) + { + fprintf (stderr, ","); + priv_ecdh = GNUNET_CRYPTO_ecdhe_key_create (); + /* Extract public keys */ + GNUNET_CRYPTO_ecdhe_key_get_public (priv_ecdh, + &id2); + /* Do ECDH */ + GNUNET_assert (GNUNET_OK == + GNUNET_CRYPTO_ecdsa_ecdh (priv_dsa, + &id2, + &dh[0])); + GNUNET_assert (GNUNET_OK == + GNUNET_CRYPTO_ecdh_ecdsa (priv_ecdh, + &id1, + &dh[1])); + /* Check that both DH results are equal. */ + GNUNET_assert (0 == memcmp (&dh[0], + &dh[1], + sizeof(struct GNUNET_HashCode))); + GNUNET_free (priv_ecdh); + } + GNUNET_free (priv_dsa); + return 0; +} + + +int +main (int argc, char *argv[]) +{ + if (! gcry_check_version ("1.6.0")) + { + fprintf (stderr, + _ ( + "libgcrypt has not the expected version (version %s is required).\n"), + "1.6.0"); + return 0; + } + if (getenv ("GNUNET_GCRYPT_DEBUG")) + gcry_control (GCRYCTL_SET_DEBUG_FLAGS, 1u, 0); + GNUNET_log_setup ("test-crypto-ecdh-ecdsa", "WARNING", NULL); + for (unsigned int i = 0; i < 4; i++) + { + fprintf (stderr, + "."); + if (0 != test_ecdh ()) + return 1; + } + return 0; +} + + +/* end of test_crypto_ecdh_ecdsa.c */ diff --git a/src/util/tweetnacl-gnunet.c b/src/util/tweetnacl-gnunet.c index 1c27730a4..f01667adb 100644 --- a/src/util/tweetnacl-gnunet.c +++ b/src/util/tweetnacl-gnunet.c @@ -424,8 +424,24 @@ GNUNET_TWEETNACL_sign_pk_from_seed (u8 *pk, const u8 *seed) d[31] &= 127; d[31] |= 64; - scalarbase (p,d); - pack (pk,p); + scalarbase (p, d); + pack (pk, p); +} + +void +GNUNET_TWEETNACL_scalarmult_gnunet_ecdsa (u8 *pk, const u8 *s) +{ + u8 d[64]; + gf p[4]; + + // Treat s as little endian. + for (u32 i = 0; i < 32; i++) + d[i] = s[31 - i]; + + // For GNUnet, we don't normalize d + + scalarbase (p, d); + pack (pk, p); } void diff --git a/src/util/tweetnacl-gnunet.h b/src/util/tweetnacl-gnunet.h index 239166ffc..d052d8824 100644 --- a/src/util/tweetnacl-gnunet.h +++ b/src/util/tweetnacl-gnunet.h @@ -47,4 +47,8 @@ GNUNET_TWEETNACL_sign_detached (uint8_t *sig, const uint8_t *m, uint64_t n, const uint8_t *sk); + +void +GNUNET_TWEETNACL_scalarmult_gnunet_ecdsa (uint8_t *pk, const uint8_t *s); + #endif diff --git a/src/vpn/gnunet-service-vpn.c b/src/vpn/gnunet-service-vpn.c index 50c990b3a..62bc45e41 100644 --- a/src/vpn/gnunet-service-vpn.c +++ b/src/vpn/gnunet-service-vpn.c @@ -2940,7 +2940,8 @@ run (void *cls, struct in6_addr v6; char *binary; - binary = GNUNET_OS_get_libexec_binary_path ("gnunet-helper-vpn"); + cfg = cfg_; + binary = GNUNET_OS_get_suid_binary_path (cfg, "gnunet-helper-vpn"); if (GNUNET_YES != GNUNET_OS_check_helper_binary ( @@ -2949,8 +2950,8 @@ run (void *cls, "-d gnunet-vpn - - 169.1.3.3.7 255.255.255.0")) // ipv4 only please! { GNUNET_log (GNUNET_ERROR_TYPE_ERROR, - "`%s' is not SUID, refusing to run.\n", - "gnunet-helper-vpn"); + "`%s' is not SUID or the path is invalid, refusing to run.\n", + binary); GNUNET_free (binary); global_ret = 1; /* we won't "really" exit here, as the 'service' is still running; @@ -2958,8 +2959,6 @@ run (void *cls, anything either */ return; } - GNUNET_free (binary); - cfg = cfg_; stats = GNUNET_STATISTICS_create ("vpn", cfg); if (GNUNET_OK != GNUNET_CONFIGURATION_get_value_number (cfg, @@ -2989,6 +2988,7 @@ run (void *cls, GNUNET_CONFIGURATION_get_value_string (cfg, "VPN", "IFNAME", &ifname)) { GNUNET_log_config_missing (GNUNET_ERROR_TYPE_ERROR, "VPN", "IFNAME"); + GNUNET_free (binary); GNUNET_SCHEDULER_shutdown (); return; } @@ -3006,6 +3006,7 @@ run (void *cls, "VPN", "IPV6ADDR", _ ("Must specify valid IPv6 address")); + GNUNET_free (binary); GNUNET_SCHEDULER_shutdown (); GNUNET_free_non_null (ipv6addr); return; @@ -3033,6 +3034,7 @@ run (void *cls, "VPN", "IPV4MASK", _ ("Must specify valid IPv6 mask")); + GNUNET_free (binary); GNUNET_SCHEDULER_shutdown (); return; } @@ -3058,6 +3060,7 @@ run (void *cls, "VPN", "IPV4ADDR", _ ("Must specify valid IPv4 address")); + GNUNET_free (binary); GNUNET_SCHEDULER_shutdown (); GNUNET_free_non_null (ipv4addr); return; @@ -3074,6 +3077,7 @@ run (void *cls, "VPN", "IPV4MASK", _ ("Must specify valid IPv4 mask")); + GNUNET_free (binary); GNUNET_SCHEDULER_shutdown (); GNUNET_free_non_null (ipv4mask); return; @@ -3093,11 +3097,12 @@ run (void *cls, cadet_handle = GNUNET_CADET_connect (cfg_); // FIXME never opens ports??? helper_handle = GNUNET_HELPER_start (GNUNET_NO, - "gnunet-helper-vpn", + binary, vpn_argv, &message_token, NULL, NULL); + GNUNET_free (binary); GNUNET_SCHEDULER_add_shutdown (&cleanup, NULL); } |