-moving code to new libgnunetgnsrecord in preparation for addressing #3052
[oweals/gnunet.git] / src / namestore / namestore_api_common.c
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
42 GNUNET_NETWORK_STRUCT_BEGIN
43
44
45 /**
46  * Internal format of a record in the serialized form.
47  */
48 struct 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
74 GNUNET_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  */
81 char *
82 GNUNET_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  */
100 const char *
101 GNUNET_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  */
127 size_t
128 GNUNET_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  */
153 ssize_t
154 GNUNET_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  */
197 int
198 GNUNET_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  */
256 int
257 GNUNET_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  */
300 struct GNUNET_TIME_Absolute
301 GNUNET_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  */
341 static void
342 derive_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  */
373 struct GNUNET_NAMESTORE_Block *
374 GNUNET_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  */
437 int
438 GNUNET_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  */
458 int
459 GNUNET_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  */
523 int
524 GNUNET_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  */
542 void
543 GNUNET_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  */
561 void
562 GNUNET_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  */
583 const char *
584 GNUNET_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  */
608 int
609 GNUNET_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 */