/** * Convert the 'value' of a record to a string. * * @param cls closure, unused * @param type type of the record * @param data value in binary encoding * @param data_size number of bytes in @a data * @return NULL on error, otherwise human-readable representation of the value */ static char * conversation_value_to_string (void *cls, uint32_t type, const void *data, size_t data_size) { char *s; switch (type) { case GNUNET_GNSRECORD_TYPE_PHONE: { const struct GNUNET_CONVERSATION_PhoneRecord *pr; char *ret; char *pkey; if (data_size != sizeof (struct GNUNET_CONVERSATION_PhoneRecord)) { GNUNET_break_op (0); return NULL; } pr = data; if (1 != ntohl (pr->version)) { GNUNET_log (GNUNET_ERROR_TYPE_ERROR, _("PHONE version %u not supported\n"), ntohl (pr->version)); return NULL; } pkey = GNUNET_CRYPTO_eddsa_public_key_to_string (&pr->peer.public_key); s = GNUNET_STRINGS_data_to_string_alloc (&pr->line_port, sizeof (struct GNUNET_HashCode)); GNUNET_asprintf (&ret, "%s-%s", s, pkey); GNUNET_free (s); GNUNET_free (pkey); return ret; } default: return NULL; } }
/** * This function updates the old token with new attributes, * removes deleted attributes and expiration times. * * @param cls the ego entry * @param tc task context */ static void handle_token_update (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc) { char *token_header; char *token_payload; char *token_payload_json; char *new_token; char *new_payload_str; char *new_payload_base64; char *sig_str; char *key; char *padding; const struct GNUNET_CRYPTO_EcdsaPrivateKey *priv_key; struct EgoEntry *ego_entry = cls; struct GNUNET_GNSRECORD_Data token_record; struct GNUNET_CRYPTO_EccSignaturePurpose *purpose; struct GNUNET_CRYPTO_EcdsaSignature sig; struct GNUNET_HashCode key_hash; struct GNUNET_TIME_Relative token_rel_exp; struct GNUNET_TIME_Relative token_ttl; struct GNUNET_TIME_Absolute token_exp; struct GNUNET_TIME_Absolute token_nbf; struct GNUNET_TIME_Absolute new_exp; struct GNUNET_TIME_Absolute new_iat; struct GNUNET_TIME_Absolute new_nbf; json_t *payload_json; json_t *value; json_t *cur_value; json_t *new_payload_json; json_t *token_nbf_json; json_t *token_exp_json; json_error_t json_err; priv_key = GNUNET_IDENTITY_ego_get_private_key (ego_entry->ego); //Note: We need the token expiration time here. Not the record expiration //time. //There are two types of tokens: Token that expire on GNS level with //an absolute expiration time. Those are basically tokens that will //be automatically revoked on (record)expiration. //Tokens stored with relative expiration times will expire on the token level (token expiration) //but this service will reissue new tokens that can be retrieved from GNS //automatically. token_header = strtok (token, "."); token_payload = strtok (NULL, "."); GNUNET_STRINGS_base64_decode (token_payload, strlen (token_payload), &token_payload_json); payload_json = json_loads (token_payload_json, JSON_DECODE_ANY, &json_err); GNUNET_free (token_payload_json); token_exp_json = json_object_get (payload_json, "exp"); token_nbf_json = json_object_get (payload_json, "nbf"); token_exp.abs_value_us = json_integer_value(token_exp_json); token_nbf.abs_value_us = json_integer_value(token_nbf_json); token_rel_exp = GNUNET_TIME_absolute_get_difference (token_nbf, token_exp); token_ttl = GNUNET_TIME_absolute_get_remaining (token_exp); if (0 != GNUNET_TIME_absolute_get_remaining (token_exp).rel_value_us) { //This token is not yet expired! Save and skip if (min_rel_exp.rel_value_us > token_ttl.rel_value_us) { min_rel_exp = token_ttl; } json_decref (payload_json); GNUNET_free (token); token = NULL; GNUNET_free (label); label = NULL; GNUNET_NAMESTORE_zone_iterator_next (ns_it); return; } GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Token is expired. Create a new one\n"); new_exp = GNUNET_TIME_relative_to_absolute (token_rel_exp); new_nbf = GNUNET_TIME_absolute_get (); new_iat = new_nbf; new_payload_json = json_object(); json_object_foreach(payload_json, key, value) { if (0 == strcmp (key, "exp")) { json_object_set_new (new_payload_json, key, json_integer (new_exp.abs_value_us)); } else if (0 == strcmp (key, "nbf")) { json_object_set_new (new_payload_json, key, json_integer (new_nbf.abs_value_us)); } else if (0 == strcmp (key, "iat")) { json_object_set_new (new_payload_json, key, json_integer (new_iat.abs_value_us)); } else if ((0 == strcmp (key, "iss")) || (0 == strcmp (key, "aud")) || (0 == strcmp (key, "sub")) || (0 == strcmp (key, "rnl"))) { json_object_set (new_payload_json, key, value); } else { GNUNET_CRYPTO_hash (key, strlen (key), &key_hash); //Check if attr still exists. omit of not if (GNUNET_NO != GNUNET_CONTAINER_multihashmap_contains (ego_entry->attr_map, &key_hash)) { cur_value = GNUNET_CONTAINER_multihashmap_get (ego_entry->attr_map, &key_hash); json_object_set (new_payload_json, key, cur_value); } } } // reassemble and set new_payload_str = json_dumps (new_payload_json, JSON_COMPACT); json_decref (payload_json); json_decref (new_payload_json); GNUNET_STRINGS_base64_encode (new_payload_str, strlen (new_payload_str), &new_payload_base64); //Remove padding padding = strtok(new_payload_base64, "="); while (NULL != padding) padding = strtok(NULL, "="); GNUNET_asprintf (&new_token, "%s,%s", token_header, new_payload_base64); purpose = GNUNET_malloc (sizeof (struct GNUNET_CRYPTO_EccSignaturePurpose) + strlen (new_token)); purpose->size = htonl (strlen (new_token) + sizeof (struct GNUNET_CRYPTO_EccSignaturePurpose)); purpose->purpose = htonl(GNUNET_SIGNATURE_PURPOSE_GNUID_TOKEN); memcpy (&purpose[1], new_token, strlen (new_token)); if (GNUNET_OK != GNUNET_CRYPTO_ecdsa_sign (priv_key, purpose, &sig)) GNUNET_break(0); GNUNET_free (new_token); sig_str = GNUNET_STRINGS_data_to_string_alloc (&sig, sizeof (struct GNUNET_CRYPTO_EcdsaSignature)); GNUNET_asprintf (&new_token, "%s.%s.%s", token_header, new_payload_base64, sig_str); GNUNET_free (sig_str); GNUNET_free (new_payload_str); GNUNET_free (new_payload_base64); GNUNET_free (purpose); token_record.data = new_token; token_record.data_size = strlen (new_token); token_record.expiration_time = new_exp.abs_value_us; token_record.record_type = GNUNET_GNSRECORD_TYPE_ID_TOKEN; token_record.flags = GNUNET_GNSRECORD_RF_NONE | GNUNET_GNSRECORD_RF_RELATIVE_EXPIRATION; ns_qe = GNUNET_NAMESTORE_records_store (ns_handle, priv_key, label, 1, &token_record, &store_token_cont, ego_entry); GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, ">>> Updating Token w/ %s\n", new_token); GNUNET_free (new_token); GNUNET_free (token); token = NULL; GNUNET_free (label); label = NULL; }