aboutsummaryrefslogtreecommitdiff
path: root/src/namestore/namestore_api_common.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/namestore/namestore_api_common.c')
-rw-r--r--src/namestore/namestore_api_common.c638
1 files changed, 0 insertions, 638 deletions
diff --git a/src/namestore/namestore_api_common.c b/src/namestore/namestore_api_common.c
deleted file mode 100644
index 388722cd3..000000000
--- a/src/namestore/namestore_api_common.c
+++ /dev/null
@@ -1,638 +0,0 @@
1/*
2 This file is part of GNUnet.
3 (C) 2009-2013 Christian Grothoff (and other contributing authors)
4
5 GNUnet is free software; you can redistribute it and/or modify
6 it under the terms of the GNU General Public License as published
7 by the Free Software Foundation; either version 3, or (at your
8 option) any later version.
9
10 GNUnet is distributed in the hope that it will be useful, but
11 WITHOUT ANY WARRANTY; without even the implied warranty of
12 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
13 General Public License for more details.
14
15 You should have received a copy of the GNU General Public License
16 along with GNUnet; see the file COPYING. If not, write to the
17 Free Software Foundation, Inc., 59 Temple Place - Suite 330,
18 Boston, MA 02111-1307, USA.
19*/
20
21/**
22 * @file namestore/namestore_api_common.c
23 * @brief API to access the NAMESTORE service
24 * @author Martin Schanzenbach
25 * @author Matthias Wachs
26 * @author Christian Grothoff
27 */
28#include "platform.h"
29#include "gnunet_util_lib.h"
30#include "gnunet_constants.h"
31#include "gnunet_signatures.h"
32#include "gnunet_arm_service.h"
33#include "gnunet_conversation_service.h"
34#include "gnunet_namestore_service.h"
35#include "gnunet_dnsparser_lib.h"
36#include "gnunet_tun_lib.h"
37#include "namestore.h"
38
39
40#define LOG(kind,...) GNUNET_log_from (kind, "namestore-api",__VA_ARGS__)
41
42GNUNET_NETWORK_STRUCT_BEGIN
43
44
45/**
46 * Internal format of a record in the serialized form.
47 */
48struct NetworkRecord
49{
50
51 /**
52 * Expiration time for the DNS record; relative or absolute depends
53 * on 'flags', network byte order.
54 */
55 uint64_t expiration_time GNUNET_PACKED;
56
57 /**
58 * Number of bytes in 'data', network byte order.
59 */
60 uint32_t data_size GNUNET_PACKED;
61
62 /**
63 * Type of the GNS/DNS record, network byte order.
64 */
65 uint32_t record_type GNUNET_PACKED;
66
67 /**
68 * Flags for the record, network byte order.
69 */
70 uint32_t flags GNUNET_PACKED;
71
72};
73
74GNUNET_NETWORK_STRUCT_END
75
76/**
77 * Convert a UTF-8 string to UTF-8 lowercase
78 * @param src source string
79 * @return converted result
80 */
81char *
82GNUNET_NAMESTORE_normalize_string (const char *src)
83{
84 GNUNET_assert (NULL != src);
85 char *res = strdup (src);
86 /* normalize */
87 GNUNET_STRINGS_utf8_tolower(src, &res);
88 return res;
89}
90
91
92/**
93 * Convert a zone key to a string (for printing debug messages).
94 * This is one of the very few calls in the entire API that is
95 * NOT reentrant!
96 *
97 * @param z the zone key
98 * @return string form; will be overwritten by next call to #GNUNET_NAMESTORE_z2s
99 */
100const char *
101GNUNET_NAMESTORE_z2s (const struct GNUNET_CRYPTO_EcdsaPublicKey *z)
102{
103 static char buf[sizeof (struct GNUNET_CRYPTO_EcdsaPublicKey) * 8];
104 char *end;
105
106 end = GNUNET_STRINGS_data_to_string ((const unsigned char *) z,
107 sizeof (struct GNUNET_CRYPTO_EcdsaPublicKey),
108 buf, sizeof (buf));
109 if (NULL == end)
110 {
111 GNUNET_break (0);
112 return NULL;
113 }
114 *end = '\0';
115 return buf;
116}
117
118
119/**
120 * Calculate how many bytes we will need to serialize the given
121 * records.
122 *
123 * @param rd_count number of records in the rd array
124 * @param rd array of #GNUNET_NAMESTORE_RecordData with @a rd_count elements
125 * @return the required size to serialize
126 */
127size_t
128GNUNET_NAMESTORE_records_get_size (unsigned int rd_count,
129 const struct GNUNET_NAMESTORE_RecordData *rd)
130{
131 unsigned int i;
132 size_t ret;
133
134 ret = sizeof (struct NetworkRecord) * rd_count;
135 for (i=0;i<rd_count;i++)
136 {
137 GNUNET_assert ((ret + rd[i].data_size) >= ret);
138 ret += rd[i].data_size;
139 }
140 return ret;
141}
142
143
144/**
145 * Serialize the given records to the given destination buffer.
146 *
147 * @param rd_count number of records in the rd array
148 * @param rd array of #GNUNET_NAMESTORE_RecordData with @a rd_count elements
149 * @param dest_size size of the destination array
150 * @param dest where to write the result
151 * @return the size of serialized records, -1 if records do not fit
152 */
153ssize_t
154GNUNET_NAMESTORE_records_serialize (unsigned int rd_count,
155 const struct GNUNET_NAMESTORE_RecordData *rd,
156 size_t dest_size,
157 char *dest)
158{
159 struct NetworkRecord rec;
160 unsigned int i;
161 size_t off;
162
163 off = 0;
164 for (i=0;i<rd_count;i++)
165 {
166 LOG (GNUNET_ERROR_TYPE_DEBUG,
167 "Serializing record %u with flags %d and expiration time %llu\n",
168 i,
169 rd[i].flags,
170 (unsigned long long) rd[i].expiration_time);
171 rec.expiration_time = GNUNET_htonll (rd[i].expiration_time);
172 rec.data_size = htonl ((uint32_t) rd[i].data_size);
173 rec.record_type = htonl (rd[i].record_type);
174 rec.flags = htonl (rd[i].flags);
175 if (off + sizeof (rec) > dest_size)
176 return -1;
177 memcpy (&dest[off], &rec, sizeof (rec));
178 off += sizeof (rec);
179 if (off + rd[i].data_size > dest_size)
180 return -1;
181 memcpy (&dest[off], rd[i].data, rd[i].data_size);
182 off += rd[i].data_size;
183 }
184 return off;
185}
186
187
188/**
189 * Compares if two records are equal (ignoring flags such
190 * as authority, private and pending, but not relative vs.
191 * absolute expiration time).
192 *
193 * @param a record
194 * @param b record
195 * @return #GNUNET_YES if the records are equal or #GNUNET_NO if they are not
196 */
197int
198GNUNET_NAMESTORE_records_cmp (const struct GNUNET_NAMESTORE_RecordData *a,
199 const struct GNUNET_NAMESTORE_RecordData *b)
200{
201 LOG (GNUNET_ERROR_TYPE_DEBUG,
202 "Comparing records\n");
203 if (a->record_type != b->record_type)
204 {
205 LOG (GNUNET_ERROR_TYPE_DEBUG,
206 "Record type %lu != %lu\n", a->record_type, b->record_type);
207 return GNUNET_NO;
208 }
209 if ((a->expiration_time != b->expiration_time) &&
210 ((a->expiration_time != 0) && (b->expiration_time != 0)))
211 {
212 LOG (GNUNET_ERROR_TYPE_DEBUG,
213 "Expiration time %llu != %llu\n",
214 a->expiration_time,
215 b->expiration_time);
216 return GNUNET_NO;
217 }
218 if ((a->flags & GNUNET_NAMESTORE_RF_RCMP_FLAGS)
219 != (b->flags & GNUNET_NAMESTORE_RF_RCMP_FLAGS))
220 {
221 LOG (GNUNET_ERROR_TYPE_DEBUG,
222 "Flags %lu (%lu) != %lu (%lu)\n", a->flags,
223 a->flags & GNUNET_NAMESTORE_RF_RCMP_FLAGS, b->flags,
224 b->flags & GNUNET_NAMESTORE_RF_RCMP_FLAGS);
225 return GNUNET_NO;
226 }
227 if (a->data_size != b->data_size)
228 {
229 LOG (GNUNET_ERROR_TYPE_DEBUG,
230 "Data size %lu != %lu\n",
231 a->data_size,
232 b->data_size);
233 return GNUNET_NO;
234 }
235 if (0 != memcmp (a->data, b->data, a->data_size))
236 {
237 LOG (GNUNET_ERROR_TYPE_DEBUG,
238 "Data contents do not match\n");
239 return GNUNET_NO;
240 }
241 LOG (GNUNET_ERROR_TYPE_DEBUG,
242 "Records are equal\n");
243 return GNUNET_YES;
244}
245
246
247/**
248 * Deserialize the given records to the given destination.
249 *
250 * @param len size of the serialized record data
251 * @param src the serialized record data
252 * @param rd_count number of records in the rd array
253 * @param dest where to put the data
254 * @return #GNUNET_OK on success, #GNUNET_SYSERR on error
255 */
256int
257GNUNET_NAMESTORE_records_deserialize (size_t len,
258 const char *src,
259 unsigned int rd_count,
260 struct GNUNET_NAMESTORE_RecordData *dest)
261{
262 struct NetworkRecord rec;
263 unsigned int i;
264 size_t off;
265
266 off = 0;
267 for (i=0;i<rd_count;i++)
268 {
269 if (off + sizeof (rec) > len)
270 return GNUNET_SYSERR;
271 memcpy (&rec, &src[off], sizeof (rec));
272 dest[i].expiration_time = GNUNET_ntohll (rec.expiration_time);
273 dest[i].data_size = ntohl ((uint32_t) rec.data_size);
274 dest[i].record_type = ntohl (rec.record_type);
275 dest[i].flags = ntohl (rec.flags);
276 off += sizeof (rec);
277 if (off + dest[i].data_size > len)
278 return GNUNET_SYSERR;
279 dest[i].data = &src[off];
280 off += dest[i].data_size;
281 LOG (GNUNET_ERROR_TYPE_DEBUG,
282 "Deserialized record %u with flags %d and expiration time %llu\n",
283 i,
284 dest[i].flags,
285 (unsigned long long) dest[i].expiration_time);
286 }
287 return GNUNET_OK;
288}
289
290
291/**
292 * Returns the expiration time of the given block of records. The block
293 * expiration time is the expiration time of the record with smallest
294 * expiration time.
295 *
296 * @param rd_count number of records given in @a rd
297 * @param rd array of records
298 * @return absolute expiration time
299 */
300struct GNUNET_TIME_Absolute
301GNUNET_NAMESTORE_record_get_expiration_time (unsigned int rd_count,
302 const struct GNUNET_NAMESTORE_RecordData *rd)
303{
304 unsigned int c;
305 struct GNUNET_TIME_Absolute expire;
306 struct GNUNET_TIME_Absolute at;
307 struct GNUNET_TIME_Relative rt;
308
309 if (NULL == rd)
310 return GNUNET_TIME_UNIT_ZERO_ABS;
311 expire = GNUNET_TIME_UNIT_FOREVER_ABS;
312 for (c = 0; c < rd_count; c++)
313 {
314 if (0 != (rd[c].flags & GNUNET_NAMESTORE_RF_RELATIVE_EXPIRATION))
315 {
316 rt.rel_value_us = rd[c].expiration_time;
317 at = GNUNET_TIME_relative_to_absolute (rt);
318 }
319 else
320 {
321 at.abs_value_us = rd[c].expiration_time;
322 }
323 expire = GNUNET_TIME_absolute_min (at, expire);
324 }
325 LOG (GNUNET_ERROR_TYPE_DEBUG,
326 "Determined expiration time for block with %u records to be %s\n",
327 rd_count,
328 GNUNET_STRINGS_absolute_time_to_string (expire));
329 return expire;
330}
331
332
333/**
334 * Derive session key and iv from label and public key.
335 *
336 * @param iv initialization vector to initialize
337 * @param skey session key to initialize
338 * @param label label to use for KDF
339 * @param pub public key to use for KDF
340 */
341static void
342derive_block_aes_key (struct GNUNET_CRYPTO_SymmetricInitializationVector *iv,
343 struct GNUNET_CRYPTO_SymmetricSessionKey *skey,
344 const char *label,
345 const struct GNUNET_CRYPTO_EcdsaPublicKey *pub)
346{
347 static const char ctx_key[] = "gns-aes-ctx-key";
348 static const char ctx_iv[] = "gns-aes-ctx-iv";
349
350 GNUNET_CRYPTO_kdf (skey, sizeof (struct GNUNET_CRYPTO_SymmetricSessionKey),
351 pub, sizeof (struct GNUNET_CRYPTO_EcdsaPublicKey),
352 label, strlen (label),
353 ctx_key, strlen (ctx_key),
354 NULL, 0);
355 GNUNET_CRYPTO_kdf (iv, sizeof (struct GNUNET_CRYPTO_SymmetricInitializationVector),
356 pub, sizeof (struct GNUNET_CRYPTO_EcdsaPublicKey),
357 label, strlen (label),
358 ctx_iv, strlen (ctx_iv),
359 NULL, 0);
360}
361
362
363/**
364 * Sign name and records
365 *
366 * @param key the private key
367 * @param expire block expiration
368 * @param label the name for the records
369 * @param rd record data
370 * @param rd_count number of records
371 * @return NULL on error (block too large)
372 */
373struct GNUNET_NAMESTORE_Block *
374GNUNET_NAMESTORE_block_create (const struct GNUNET_CRYPTO_EcdsaPrivateKey *key,
375 struct GNUNET_TIME_Absolute expire,
376 const char *label,
377 const struct GNUNET_NAMESTORE_RecordData *rd,
378 unsigned int rd_count)
379{
380 size_t payload_len = GNUNET_NAMESTORE_records_get_size (rd_count, rd);
381 char payload[sizeof (uint32_t) + payload_len];
382 struct GNUNET_NAMESTORE_Block *block;
383 struct GNUNET_CRYPTO_EcdsaPublicKey pkey;
384 struct GNUNET_CRYPTO_EcdsaPrivateKey *dkey;
385 struct GNUNET_CRYPTO_SymmetricInitializationVector iv;
386 struct GNUNET_CRYPTO_SymmetricSessionKey skey;
387 uint32_t rd_count_nbo;
388
389 if (payload_len > GNUNET_NAMESTORE_MAX_VALUE_SIZE)
390 return NULL;
391 rd_count_nbo = htonl (rd_count);
392 memcpy (payload, &rd_count_nbo, sizeof (uint32_t));
393 GNUNET_assert (payload_len ==
394 GNUNET_NAMESTORE_records_serialize (rd_count, rd,
395 payload_len, &payload[sizeof (uint32_t)]));
396 block = GNUNET_malloc (sizeof (struct GNUNET_NAMESTORE_Block) +
397 sizeof (uint32_t) + payload_len);
398 block->purpose.size = htonl (sizeof (uint32_t) + payload_len +
399 sizeof (struct GNUNET_CRYPTO_EccSignaturePurpose) +
400 sizeof (struct GNUNET_TIME_AbsoluteNBO));
401 block->purpose.purpose = htonl (GNUNET_SIGNATURE_PURPOSE_GNS_RECORD_SIGN);
402 block->expiration_time = GNUNET_TIME_absolute_hton (expire);
403 dkey = GNUNET_CRYPTO_ecdsa_private_key_derive (key,
404 label,
405 "gns");
406 GNUNET_CRYPTO_ecdsa_key_get_public (dkey,
407 &block->derived_key);
408 GNUNET_CRYPTO_ecdsa_key_get_public (key,
409 &pkey);
410 derive_block_aes_key (&iv, &skey, label, &pkey);
411 GNUNET_break (payload_len + sizeof (uint32_t) ==
412 GNUNET_CRYPTO_symmetric_encrypt (payload, payload_len + sizeof (uint32_t),
413 &skey, &iv,
414 &block[1]));
415 if (GNUNET_OK !=
416 GNUNET_CRYPTO_ecdsa_sign (dkey,
417 &block->purpose,
418 &block->signature))
419 {
420 GNUNET_break (0);
421 GNUNET_free (dkey);
422 GNUNET_free (block);
423 return NULL;
424 }
425 GNUNET_free (dkey);
426 return block;
427}
428
429
430/**
431 * Check if a signature is valid. This API is used by the GNS Block
432 * to validate signatures received from the network.
433 *
434 * @param block block to verify
435 * @return #GNUNET_OK if the signature is valid
436 */
437int
438GNUNET_NAMESTORE_block_verify (const struct GNUNET_NAMESTORE_Block *block)
439{
440 return GNUNET_CRYPTO_ecdsa_verify (GNUNET_SIGNATURE_PURPOSE_GNS_RECORD_SIGN,
441 &block->purpose,
442 &block->signature,
443 &block->derived_key);
444}
445
446
447/**
448 * Decrypt block.
449 *
450 * @param block block to decrypt
451 * @param zone_key public key of the zone
452 * @param label the name for the records
453 * @param proc function to call with the result
454 * @param proc_cls closure for proc
455 * @return #GNUNET_OK on success, #GNUNET_SYSERR if the block was
456 * not well-formed
457 */
458int
459GNUNET_NAMESTORE_block_decrypt (const struct GNUNET_NAMESTORE_Block *block,
460 const struct GNUNET_CRYPTO_EcdsaPublicKey *zone_key,
461 const char *label,
462 GNUNET_NAMESTORE_RecordCallback proc,
463 void *proc_cls)
464{
465 size_t payload_len = ntohl (block->purpose.size) -
466 sizeof (struct GNUNET_CRYPTO_EccSignaturePurpose) -
467 sizeof (struct GNUNET_TIME_AbsoluteNBO);
468 struct GNUNET_CRYPTO_SymmetricInitializationVector iv;
469 struct GNUNET_CRYPTO_SymmetricSessionKey skey;
470
471 if (ntohl (block->purpose.size) <
472 sizeof (struct GNUNET_CRYPTO_EccSignaturePurpose) +
473 sizeof (struct GNUNET_TIME_AbsoluteNBO))
474 {
475 GNUNET_break_op (0);
476 return GNUNET_SYSERR;
477 }
478 derive_block_aes_key (&iv, &skey, label, zone_key);
479 {
480 char payload[payload_len];
481 uint32_t rd_count;
482
483 GNUNET_break (payload_len ==
484 GNUNET_CRYPTO_symmetric_decrypt (&block[1], payload_len,
485 &skey, &iv,
486 payload));
487 memcpy (&rd_count,
488 payload,
489 sizeof (uint32_t));
490 rd_count = ntohl (rd_count);
491 if (rd_count > 2048)
492 {
493 /* limit to sane value */
494 GNUNET_break_op (0);
495 return GNUNET_SYSERR;
496 }
497 {
498 struct GNUNET_NAMESTORE_RecordData rd[rd_count];
499
500 if (GNUNET_OK !=
501 GNUNET_NAMESTORE_records_deserialize (payload_len - sizeof (uint32_t),
502 &payload[sizeof (uint32_t)],
503 rd_count,
504 rd))
505 {
506 GNUNET_break_op (0);
507 return GNUNET_SYSERR;
508 }
509 if (NULL != proc)
510 proc (proc_cls, rd_count, (0 != rd_count) ? rd : NULL);
511 }
512 }
513 return GNUNET_OK;
514}
515
516
517/**
518 * Test if a given record is expired.
519 *
520 * @return #GNUNET_YES if the record is expired,
521 * #GNUNET_NO if not
522 */
523int
524GNUNET_NAMESTORE_is_expired (const struct GNUNET_NAMESTORE_RecordData *rd)
525{
526 struct GNUNET_TIME_Absolute at;
527
528 if (0 != (rd->flags & GNUNET_NAMESTORE_RF_RELATIVE_EXPIRATION))
529 return GNUNET_NO;
530 at.abs_value_us = rd->expiration_time;
531 return (0 == GNUNET_TIME_absolute_get_remaining (at).rel_value_us) ? GNUNET_YES : GNUNET_NO;
532}
533
534
535/**
536 * Calculate the DHT query for a given @a label in a given @a zone.
537 *
538 * @param zone private key of the zone
539 * @param label label of the record
540 * @param query hash to use for the query
541 */
542void
543GNUNET_NAMESTORE_query_from_private_key (const struct GNUNET_CRYPTO_EcdsaPrivateKey *zone,
544 const char *label,
545 struct GNUNET_HashCode *query)
546{
547 struct GNUNET_CRYPTO_EcdsaPublicKey pub;
548
549 GNUNET_CRYPTO_ecdsa_key_get_public (zone, &pub);
550 GNUNET_NAMESTORE_query_from_public_key (&pub, label, query);
551}
552
553
554/**
555 * Calculate the DHT query for a given @a label in a given @a zone.
556 *
557 * @param pub public key of the zone
558 * @param label label of the record
559 * @param query hash to use for the query
560 */
561void
562GNUNET_NAMESTORE_query_from_public_key (const struct GNUNET_CRYPTO_EcdsaPublicKey *pub,
563 const char *label,
564 struct GNUNET_HashCode *query)
565{
566 struct GNUNET_CRYPTO_EcdsaPublicKey pd;
567
568 GNUNET_CRYPTO_ecdsa_public_key_derive (pub, label, "gns", &pd);
569 GNUNET_CRYPTO_hash (&pd, sizeof (pd), query);
570}
571
572
573/**
574 * Convert public key to the respective absolute domain name in the
575 * ".zkey" pTLD.
576 * This is one of the very few calls in the entire API that is
577 * NOT reentrant!
578 *
579 * @param pkey a public key with a point on the eliptic curve
580 * @return string "X.zkey" where X is the public
581 * key in an encoding suitable for DNS labels.
582 */
583const char *
584GNUNET_NAMESTORE_pkey_to_zkey (const struct GNUNET_CRYPTO_EcdsaPublicKey *pkey)
585{
586 static char ret[128];
587 char *pkeys;
588
589 pkeys = GNUNET_CRYPTO_ecdsa_public_key_to_string (pkey);
590 GNUNET_snprintf (ret,
591 sizeof (ret),
592 "%s.zkey",
593 pkeys);
594 GNUNET_free (pkeys);
595 return ret;
596}
597
598
599/**
600 * Convert an absolute domain name in the ".zkey" pTLD to the
601 * respective public key.
602 *
603 * @param zkey string "X.zkey" where X is the coordinates of the public
604 * key in an encoding suitable for DNS labels.
605 * @param pkey set to a public key on the eliptic curve
606 * @return #GNUNET_SYSERR if @a zkey has the wrong syntax
607 */
608int
609GNUNET_NAMESTORE_zkey_to_pkey (const char *zkey,
610 struct GNUNET_CRYPTO_EcdsaPublicKey *pkey)
611{
612 char *cpy;
613 char *dot;
614 const char *x;
615
616 cpy = GNUNET_strdup (zkey);
617 x = cpy;
618 if (NULL == (dot = strchr (x, (int) '.')))
619 goto error;
620 *dot = '\0';
621 if (0 != strcasecmp (dot + 1,
622 "zkey"))
623 goto error;
624
625 if (GNUNET_OK !=
626 GNUNET_CRYPTO_ecdsa_public_key_from_string (x,
627 strlen (x),
628 pkey))
629 goto error;
630 GNUNET_free (cpy);
631 return GNUNET_OK;
632 error:
633 GNUNET_free (cpy);
634 return GNUNET_SYSERR;
635}
636
637
638/* end of namestore_common.c */