/** * Sign name and records * * @param key the private key * @param expire block expiration * @param name the name * @param rd record data * @param rd_count number of records * * @return the signature */ struct GNUNET_CRYPTO_RsaSignature * GNUNET_NAMESTORE_create_signature (const struct GNUNET_CRYPTO_RsaPrivateKey *key, struct GNUNET_TIME_Absolute expire, const char *name, const struct GNUNET_NAMESTORE_RecordData *rd, unsigned int rd_count) { struct GNUNET_CRYPTO_RsaSignature *sig; struct GNUNET_CRYPTO_RsaSignaturePurpose *sig_purpose; struct GNUNET_TIME_AbsoluteNBO expire_nbo; size_t rd_ser_len; size_t name_len; struct GNUNET_TIME_AbsoluteNBO *expire_tmp; char * name_tmp; char * rd_tmp; int res; uint32_t sig_len; if (NULL == name) { GNUNET_break (0); return NULL; } sig = GNUNET_malloc (sizeof (struct GNUNET_CRYPTO_RsaSignature)); name_len = strlen (name) + 1; expire_nbo = GNUNET_TIME_absolute_hton (expire); rd_ser_len = GNUNET_NAMESTORE_records_get_size (rd_count, rd); { char rd_ser[rd_ser_len]; GNUNET_assert (rd_ser_len == GNUNET_NAMESTORE_records_serialize (rd_count, rd, rd_ser_len, rd_ser)); sig_len = sizeof (struct GNUNET_CRYPTO_RsaSignaturePurpose) + sizeof (struct GNUNET_TIME_AbsoluteNBO) + rd_ser_len + name_len; sig_purpose = GNUNET_malloc (sig_len); sig_purpose->size = htonl (sig_len); sig_purpose->purpose = htonl (GNUNET_SIGNATURE_PURPOSE_GNS_RECORD_SIGN); expire_tmp = (struct GNUNET_TIME_AbsoluteNBO *) &sig_purpose[1]; memcpy (expire_tmp, &expire_nbo, sizeof (struct GNUNET_TIME_AbsoluteNBO)); name_tmp = (char *) &expire_tmp[1]; memcpy (name_tmp, name, name_len); rd_tmp = &name_tmp[name_len]; memcpy (rd_tmp, rd_ser, rd_ser_len); res = GNUNET_CRYPTO_rsa_sign (key, sig_purpose, sig); GNUNET_free (sig_purpose); } if (GNUNET_OK != res) { GNUNET_break (0); GNUNET_free (sig); return NULL; } return sig; }
/** * Check if a signature is valid. This API is used by the GNS Block * to validate signatures received from the network. * * @param public_key public key of the zone * @param expire block expiration * @param name name that is being mapped (at most 255 characters long) * @param rd_count number of entries in 'rd' array * @param rd array of records with data to store * @param signature signature for all the records in the zone under the given name * @return GNUNET_OK if the signature is valid */ int GNUNET_NAMESTORE_verify_signature (const struct GNUNET_CRYPTO_RsaPublicKeyBinaryEncoded *public_key, const struct GNUNET_TIME_Absolute expire, const char *name, unsigned int rd_count, const struct GNUNET_NAMESTORE_RecordData *rd, const struct GNUNET_CRYPTO_RsaSignature *signature) { int res = GNUNET_SYSERR; size_t rd_ser_len = 0; size_t name_len = 0; char * name_tmp; char * rd_tmp; struct GNUNET_CRYPTO_RsaSignaturePurpose *sig_purpose; struct GNUNET_TIME_AbsoluteNBO *expire_tmp; struct GNUNET_TIME_AbsoluteNBO expire_nbo = GNUNET_TIME_absolute_hton(expire); GNUNET_assert (public_key != NULL); GNUNET_assert (name != NULL); GNUNET_assert (rd != NULL); GNUNET_assert (signature != NULL); rd_ser_len = GNUNET_NAMESTORE_records_get_size(rd_count, rd); char rd_ser[rd_ser_len]; GNUNET_NAMESTORE_records_serialize(rd_count, rd, rd_ser_len, rd_ser); name_len = strlen (name) + 1; if (name_len > 256) { GNUNET_break (0); return GNUNET_SYSERR; } sig_purpose = GNUNET_malloc(sizeof (struct GNUNET_CRYPTO_RsaSignaturePurpose) + sizeof (struct GNUNET_TIME_AbsoluteNBO) + rd_ser_len + name_len); sig_purpose->size = htonl (sizeof (struct GNUNET_CRYPTO_RsaSignaturePurpose)+ rd_ser_len + name_len); sig_purpose->purpose = htonl (GNUNET_SIGNATURE_PURPOSE_GNS_RECORD_SIGN); expire_tmp = (struct GNUNET_TIME_AbsoluteNBO *) &sig_purpose[1]; name_tmp = (char *) &expire_tmp[1]; rd_tmp = &name_tmp[name_len]; memcpy (expire_tmp, &expire_nbo, sizeof (struct GNUNET_TIME_AbsoluteNBO)); memcpy (name_tmp, name, name_len); memcpy (rd_tmp, rd_ser, rd_ser_len); res = GNUNET_CRYPTO_rsa_verify(GNUNET_SIGNATURE_PURPOSE_GNS_RECORD_SIGN, sig_purpose, signature, public_key); GNUNET_free (sig_purpose); return res; }
static void run (void *cls, char *const *args, const char *cfgfile, const struct GNUNET_CONFIGURATION_Handle *cfg) { delete_existing_db(cfg); endbadly_task = GNUNET_SCHEDULER_add_delayed(TIMEOUT,endbadly, NULL); size_t rd_ser_len; /* load privat key from file not included in zonekey dir */ privkey = GNUNET_CRYPTO_rsa_key_create_from_file("test_hostkey"); GNUNET_assert (privkey != NULL); /* get public key */ GNUNET_CRYPTO_rsa_key_get_public(privkey, &pubkey); /* create record */ s_name = "dummy.dummy.gnunet"; s_rd = create_record (RECORDS); rd_ser_len = GNUNET_NAMESTORE_records_get_size(RECORDS, s_rd); char rd_ser[rd_ser_len]; GNUNET_NAMESTORE_records_serialize(RECORDS, s_rd, rd_ser_len, rd_ser); /* sign */ s_signature = GNUNET_NAMESTORE_create_signature(privkey, s_rd[0].expiration, s_name, s_rd, RECORDS); /* create random zone hash */ GNUNET_CRYPTO_short_hash (&pubkey, sizeof (struct GNUNET_CRYPTO_RsaPublicKeyBinaryEncoded), &s_zone); start_arm (cfgfile); GNUNET_assert (arm != NULL); nsh = GNUNET_NAMESTORE_connect (cfg); GNUNET_break (NULL != nsh); GNUNET_break (s_rd != NULL); GNUNET_break (s_name != NULL); GNUNET_NAMESTORE_record_put (nsh, &pubkey, s_name, GNUNET_TIME_UNIT_FOREVER_ABS, RECORDS, s_rd, s_signature, put_cont, s_name); }
/** * Reply to client with the result from our lookup. * * @param cls the closure (our client lookup handle) * @param rd_count the number of records * @param rd the record data */ static void send_lookup_response(void* cls, uint32_t rd_count, const struct GNUNET_NAMESTORE_RecordData *rd) { struct ClientLookupHandle* clh = (struct ClientLookupHandle*)cls; struct GNUNET_GNS_ClientLookupResultMessage *rmsg; size_t len; GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Sending `%s' message with %d results\n", "LOOKUP_RESULT", rd_count); len = GNUNET_NAMESTORE_records_get_size (rd_count, rd); rmsg = GNUNET_malloc(len+sizeof(struct GNUNET_GNS_ClientLookupResultMessage)); rmsg->id = clh->unique_id; rmsg->rd_count = htonl(rd_count); rmsg->header.type = htons(GNUNET_MESSAGE_TYPE_GNS_LOOKUP_RESULT); rmsg->header.size = htons(len+sizeof(struct GNUNET_GNS_ClientLookupResultMessage)); GNUNET_NAMESTORE_records_serialize (rd_count, rd, len, (char*)&rmsg[1]); GNUNET_SERVER_notification_context_unicast (nc, clh->client, (const struct GNUNET_MessageHeader *) rmsg, GNUNET_NO); GNUNET_SERVER_receive_done (clh->client, GNUNET_OK); GNUNET_free(rmsg); GNUNET_free(clh->name); if (NULL != clh->zone_key) GNUNET_free(clh->zone_key); GNUNET_free(clh); }
/** * Function used to put all records successively into the DHT. * * @param cls the closure (NULL) * @param key the public key of the authority (ours) * @param expiration lifetime of the namestore entry * @param name the name of the records * @param rd_count the number of records in data * @param rd the record data * @param signature the signature for the record data */ static void put_gns_record(void *cls, const struct GNUNET_CRYPTO_RsaPublicKeyBinaryEncoded *key, struct GNUNET_TIME_Absolute expiration, const char *name, unsigned int rd_count, const struct GNUNET_NAMESTORE_RecordData *rd, const struct GNUNET_CRYPTO_RsaSignature *signature) { struct GNSNameRecordBlock *nrb; struct GNUNET_CRYPTO_ShortHashCode name_hash; struct GNUNET_CRYPTO_ShortHashCode zhash; GNUNET_HashCode xor_hash; GNUNET_HashCode name_hash_double; GNUNET_HashCode zone_hash_double; uint32_t rd_payload_length; char* nrb_data = NULL; size_t namelen; /* we're done */ if (NULL == name) { GNUNET_log(GNUNET_ERROR_TYPE_DEBUG, "Zone iteration finished. Rescheduling put in %ds\n", dht_max_update_interval); zone_update_taskid = GNUNET_SCHEDULER_add_delayed ( GNUNET_TIME_relative_multiply( GNUNET_TIME_UNIT_SECONDS, dht_max_update_interval ), &update_zone_dht_start, NULL); return; } namelen = strlen(name) + 1; if (signature == NULL) { GNUNET_log(GNUNET_ERROR_TYPE_ERROR, "No signature for %s record data provided! Skipping...\n", name); zone_update_taskid = GNUNET_SCHEDULER_add_now (&update_zone_dht_next, NULL); return; } GNUNET_log(GNUNET_ERROR_TYPE_DEBUG, "Putting records for %s into the DHT\n", name); rd_payload_length = GNUNET_NAMESTORE_records_get_size (rd_count, rd); nrb = GNUNET_malloc(rd_payload_length + namelen + sizeof(struct GNSNameRecordBlock)); nrb->signature = *signature; nrb->public_key = *key; nrb->rd_count = htonl(rd_count); memcpy(&nrb[1], name, namelen); nrb_data = (char*)&nrb[1]; nrb_data += namelen; rd_payload_length += sizeof(struct GNSNameRecordBlock) + namelen; if (-1 == GNUNET_NAMESTORE_records_serialize (rd_count, rd, rd_payload_length, nrb_data)) { GNUNET_log(GNUNET_ERROR_TYPE_ERROR, "Record serialization failed! Skipping...\n"); GNUNET_free(nrb); zone_update_taskid = GNUNET_SCHEDULER_add_now (&update_zone_dht_next, NULL); return; } /* * calculate DHT key: H(name) xor H(pubkey) */ GNUNET_CRYPTO_short_hash(key, sizeof(struct GNUNET_CRYPTO_RsaPublicKeyBinaryEncoded), &zhash); GNUNET_CRYPTO_short_hash(name, strlen(name), &name_hash); GNUNET_CRYPTO_short_hash_double (&name_hash, &name_hash_double); GNUNET_CRYPTO_short_hash_double (&zhash, &zone_hash_double); GNUNET_CRYPTO_hash_xor(&zone_hash_double, &name_hash_double, &xor_hash); GNUNET_log(GNUNET_ERROR_TYPE_DEBUG, "zone identity: %s\n", GNUNET_h2s (&zone_hash_double)); GNUNET_log(GNUNET_ERROR_TYPE_DEBUG, "putting records for %s under key: %s with size %d\n", name, GNUNET_h2s (&xor_hash), rd_payload_length); GNUNET_log(GNUNET_ERROR_TYPE_DEBUG, "DHT req to %d\n", DHT_OPERATION_TIMEOUT.rel_value); /* FIXME: keep return value to possibly cancel? */ GNUNET_DHT_put (dht_handle, &xor_hash, DHT_GNS_REPLICATION_LEVEL, GNUNET_DHT_RO_NONE, GNUNET_BLOCK_TYPE_GNS_NAMERECORD, rd_payload_length, (char*)nrb, expiration, DHT_OPERATION_TIMEOUT, &record_dht_put, NULL); //cls for cont num_public_records++; /** * Reschedule periodic put */ zone_update_taskid = GNUNET_SCHEDULER_add_delayed (record_put_interval, &update_zone_dht_next, NULL); GNUNET_free(nrb); }
/** * Store an item in the namestore. If the item is already present, * the expiration time is updated to the max of the existing time and * the new time. This API is used when we cache signatures from other * authorities. * * @param h handle to the namestore * @param zone_key public key of the zone * @param name name that is being mapped (at most 255 characters long) * @param freshness when does the corresponding block in the DHT expire (until * when should we never do a DHT lookup for the same name again)? * @param rd_count number of entries in 'rd' array * @param rd array of records with data to store * @param signature signature for all the records in the zone under the given name * @param cont continuation to call when done * @param cont_cls closure for cont * @return handle to abort the request */ struct GNUNET_NAMESTORE_QueueEntry * GNUNET_NAMESTORE_record_put (struct GNUNET_NAMESTORE_Handle *h, const struct GNUNET_CRYPTO_RsaPublicKeyBinaryEncoded *zone_key, const char *name, struct GNUNET_TIME_Absolute freshness, unsigned int rd_count, const struct GNUNET_NAMESTORE_RecordData *rd, const struct GNUNET_CRYPTO_RsaSignature *signature, GNUNET_NAMESTORE_ContinuationWithStatus cont, void *cont_cls) { struct GNUNET_NAMESTORE_QueueEntry *qe; struct PendingMessage *pe; /* pointer to elements */ char * rd_tmp; char * name_tmp; size_t msg_size = 0; size_t name_len = 0; size_t rd_ser_len = 0; uint32_t rid = 0; GNUNET_assert (NULL != h); GNUNET_assert (NULL != zone_key); GNUNET_assert (NULL != name); GNUNET_assert (NULL != rd); GNUNET_assert (NULL != signature); name_len = strlen(name) + 1; if (name_len > 256) { GNUNET_break (0); return NULL; } rid = get_op_id(h); qe = GNUNET_malloc(sizeof (struct GNUNET_NAMESTORE_QueueEntry)); qe->nsh = h; qe->cont = cont; qe->cont_cls = cont_cls; qe->op_id = rid; GNUNET_CONTAINER_DLL_insert_tail(h->op_head, h->op_tail, qe); /* set msg_size*/ rd_ser_len = GNUNET_NAMESTORE_records_get_size(rd_count, rd); char rd_ser[rd_ser_len]; GNUNET_NAMESTORE_records_serialize(rd_count, rd, rd_ser_len, rd_ser); struct RecordPutMessage * msg; msg_size = sizeof (struct RecordPutMessage) + name_len + rd_ser_len; /* create msg here */ pe = GNUNET_malloc(sizeof (struct PendingMessage) + msg_size); pe->size = msg_size; pe->is_init = GNUNET_NO; msg = (struct RecordPutMessage *) &pe[1]; name_tmp = (char *) &msg[1]; rd_tmp = &name_tmp[name_len]; msg->gns_header.header.type = htons (GNUNET_MESSAGE_TYPE_NAMESTORE_RECORD_PUT); msg->gns_header.header.size = htons (msg_size); msg->gns_header.r_id = htonl (rid); msg->signature = *signature; msg->name_len = htons (name_len); msg->expire = GNUNET_TIME_absolute_hton (freshness); msg->rd_len = htons (rd_ser_len); msg->rd_count = htons (rd_count); msg->public_key = *zone_key; memcpy (name_tmp, name, name_len); memcpy (rd_tmp, rd_ser, rd_ser_len); GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Sending `%s' message for name `%s' with size %u\n", "NAMESTORE_RECORD_PUT", name, msg_size); GNUNET_CONTAINER_DLL_insert_tail (h->pending_head, h->pending_tail, pe); do_transmit(h); return qe; }
/** * Explicitly remove some content from the database. The * "cont"inuation will be called with status "GNUNET_OK" if content * was removed, "GNUNET_NO" if no matching entry was found and * "GNUNET_SYSERR" on all other types of errors. * This API is used by the authority of a zone. * * @param h handle to the namestore * @param pkey private key of the zone * @param name name that is being mapped (at most 255 characters long) * @param rd record data, remove specific record, NULL to remove the name and all records * @param cont continuation to call when done * @param cont_cls closure for cont * @return handle to abort the request */ struct GNUNET_NAMESTORE_QueueEntry * GNUNET_NAMESTORE_record_remove (struct GNUNET_NAMESTORE_Handle *h, const struct GNUNET_CRYPTO_RsaPrivateKey *pkey, const char *name, const struct GNUNET_NAMESTORE_RecordData *rd, GNUNET_NAMESTORE_ContinuationWithStatus cont, void *cont_cls) { struct GNUNET_NAMESTORE_QueueEntry *qe; struct PendingMessage *pe; char *pkey_tmp; char *rd_tmp; char *name_tmp; size_t rd_ser_len = 0; size_t msg_size = 0; size_t name_len = 0; size_t key_len = 0; uint32_t rid = 0; uint16_t rd_count = 1; GNUNET_assert (NULL != h); rid = get_op_id(h); qe = GNUNET_malloc(sizeof (struct GNUNET_NAMESTORE_QueueEntry)); qe->nsh = h; qe->cont = cont; qe->cont_cls = cont_cls; qe->op_id = rid; GNUNET_CONTAINER_DLL_insert_tail(h->op_head, h->op_tail, qe); /* set msg_size*/ struct GNUNET_CRYPTO_RsaPrivateKeyBinaryEncoded * pkey_enc = GNUNET_CRYPTO_rsa_encode_key (pkey); GNUNET_assert (pkey_enc != NULL); key_len = ntohs (pkey_enc->len); if (NULL == rd) rd_count = 0; else rd_count = 1; rd_ser_len = GNUNET_NAMESTORE_records_get_size (rd_count, rd); char rd_ser[rd_ser_len]; GNUNET_NAMESTORE_records_serialize (rd_count, rd, rd_ser_len, rd_ser); name_len = strlen (name) + 1; struct RecordRemoveMessage * msg; msg_size = sizeof (struct RecordRemoveMessage) + key_len + name_len + rd_ser_len; /* create msg here */ pe = GNUNET_malloc(sizeof (struct PendingMessage) + msg_size); pe->size = msg_size; pe->is_init = GNUNET_NO; msg = (struct RecordRemoveMessage *) &pe[1]; pkey_tmp = (char *) &msg[1]; name_tmp = &pkey_tmp[key_len]; rd_tmp = &name_tmp[name_len]; msg->gns_header.header.type = htons (GNUNET_MESSAGE_TYPE_NAMESTORE_RECORD_REMOVE); msg->gns_header.header.size = htons (msg_size); msg->gns_header.r_id = htonl (rid); msg->name_len = htons (name_len); msg->rd_len = htons (rd_ser_len); msg->rd_count = htons (rd_count); msg->pkey_len = htons (key_len); memcpy (pkey_tmp, pkey_enc, key_len); memcpy (name_tmp, name, name_len); memcpy (rd_tmp, rd_ser, rd_ser_len); GNUNET_free (pkey_enc); GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Sending `%s' message for name `%s' with size %u\n", "NAMESTORE_RECORD_REMOVE", name, msg_size); GNUNET_CONTAINER_DLL_insert_tail (h->pending_head, h->pending_tail, pe); do_transmit(h); return qe; }
static void run (void *cls, char *const *args, const char *cfgfile, const struct GNUNET_CONFIGURATION_Handle *cfg) { size_t len; int c; int rd_count = 3; size_t data_len; struct GNUNET_NAMESTORE_RecordData src[rd_count]; memset(src, '\0', rd_count * sizeof (struct GNUNET_NAMESTORE_RecordData)); data_len = 0; for (c = 0; c < rd_count; c++) { src[c].record_type = c+1; src[c].data_size = data_len; src[c].data = GNUNET_malloc (data_len); /* Setting data to data_len * record_type */ memset ((char *) src[c].data, 'a', data_len); data_len += 10; } res = 0; len = GNUNET_NAMESTORE_records_get_size(rd_count, src); char rd_ser[len]; GNUNET_assert (len == GNUNET_NAMESTORE_records_serialize(rd_count, src, len, rd_ser)); GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Serialized data len: %u\n",len); GNUNET_assert (rd_ser != NULL); struct GNUNET_NAMESTORE_RecordData dst[rd_count]; GNUNET_assert (GNUNET_OK == GNUNET_NAMESTORE_records_deserialize (len, rd_ser, rd_count, dst)); GNUNET_assert (dst != NULL); for (c = 0; c < rd_count; c++) { if (src[c].data_size != dst[c].data_size) { GNUNET_break (0); res = 1; } if (0 != GNUNET_TIME_absolute_get_difference(src[c].expiration, dst[c].expiration).rel_value) { GNUNET_break (0); res = 1; } if (src[c].flags != dst[c].flags) { GNUNET_break (0); res = 1; } if (src[c].record_type != dst[c].record_type) { GNUNET_break (0); res = 1; } size_t data_size = src[c].data_size; char data[data_size]; memset (data, 'a', data_size); if (0 != memcmp (data, dst[c].data, data_size)) { GNUNET_break (0); res = 1; } if (0 != memcmp (data, src[c].data, data_size)) { GNUNET_break (0); res = 1; } if (0 != memcmp (src[c].data, dst[c].data, src[c].data_size)) { GNUNET_break (0); res = 1; } GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Element [%i]: EQUAL\n", c); } for (c = 0; c < rd_count; c++) { GNUNET_free ((void *)src[c].data); } }