aboutsummaryrefslogtreecommitdiff
path: root/src/gnsrecord
diff options
context:
space:
mode:
authorChristian Grothoff <christian@grothoff.org>2013-10-16 20:14:02 +0000
committerChristian Grothoff <christian@grothoff.org>2013-10-16 20:14:02 +0000
commit3d670727232e79b7e49a1df7ba9260db4e5798a0 (patch)
tree093f7b5aec28134dc6c5fe34cd2d8bfb1e1445ad /src/gnsrecord
parent2de26776993a5e591e487321a5dc1d62b86d9cd4 (diff)
downloadgnunet-3d670727232e79b7e49a1df7ba9260db4e5798a0.tar.gz
gnunet-3d670727232e79b7e49a1df7ba9260db4e5798a0.zip
-moving namestore_common functions to gnsrecord library
Diffstat (limited to 'src/gnsrecord')
-rw-r--r--src/gnsrecord/Makefile.am23
-rw-r--r--src/gnsrecord/gnsrecord_crypto.c263
-rw-r--r--src/gnsrecord/gnsrecord_misc.c267
-rw-r--r--src/gnsrecord/gnsrecord_serialization.c188
-rw-r--r--src/gnsrecord/test_gnsrecord_crypto.c145
-rw-r--r--src/gnsrecord/test_gnsrecord_serialization.c140
6 files changed, 1025 insertions, 1 deletions
diff --git a/src/gnsrecord/Makefile.am b/src/gnsrecord/Makefile.am
index 2fb859f39..1f489c8d7 100644
--- a/src/gnsrecord/Makefile.am
+++ b/src/gnsrecord/Makefile.am
@@ -15,6 +15,10 @@ if USE_COVERAGE
15 XLIBS = -lgcov 15 XLIBS = -lgcov
16endif 16endif
17 17
18check_PROGRAMS = \
19 test_gnsrecord_crypto \
20 test_gnsrecord_serialization
21
18if ENABLE_TEST_RUN 22if ENABLE_TEST_RUN
19TESTS = \ 23TESTS = \
20 $(check_PROGRAMS) \ 24 $(check_PROGRAMS) \
@@ -25,7 +29,10 @@ lib_LTLIBRARIES = \
25 libgnunetgnsrecord.la 29 libgnunetgnsrecord.la
26 30
27libgnunetgnsrecord_la_SOURCES = \ 31libgnunetgnsrecord_la_SOURCES = \
28 gnsrecord.c 32 gnsrecord.c \
33 gnsrecord_serialization.c \
34 gnsrecord_crypto.c \
35 gnsrecord_misc.c
29libgnunetgnsrecord_la_LIBADD = \ 36libgnunetgnsrecord_la_LIBADD = \
30 $(top_builddir)/src/dns/libgnunetdnsparser.la \ 37 $(top_builddir)/src/dns/libgnunetdnsparser.la \
31 $(top_builddir)/src/util/libgnunetutil.la \ 38 $(top_builddir)/src/util/libgnunetutil.la \
@@ -52,3 +59,17 @@ libgnunet_plugin_gnsrecord_dns_la_LDFLAGS = \
52EXTRA_DIST = \ 59EXTRA_DIST = \
53 $(check_SCRIPTS) 60 $(check_SCRIPTS)
54 61
62test_gnsrecord_serialization_SOURCES = \
63 test_gnsrecord_serialization.c
64test_gnsrecord_serialization_LDADD = \
65 $(top_builddir)/src/testing/libgnunettesting.la \
66 $(top_builddir)/src/gnsrecord/libgnunetgnsrecord.la \
67 $(top_builddir)/src/util/libgnunetutil.la
68
69test_gnsrecord_crypto_SOURCES = \
70 test_gnsrecord_crypto.c
71test_gnsrecord_crypto_LDADD = \
72 $(top_builddir)/src/testing/libgnunettesting.la \
73 $(top_builddir)/src/gnsrecord/libgnunetgnsrecord.la \
74 $(top_builddir)/src/util/libgnunetutil.la
75
diff --git a/src/gnsrecord/gnsrecord_crypto.c b/src/gnsrecord/gnsrecord_crypto.c
new file mode 100644
index 000000000..823ffcae3
--- /dev/null
+++ b/src/gnsrecord/gnsrecord_crypto.c
@@ -0,0 +1,263 @@
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 gnsrecord/gnsrecord_crypto.c
23 * @brief API for GNS record-related crypto
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_gnsrecord_lib.h"
34#include "gnunet_dnsparser_lib.h"
35#include "gnunet_tun_lib.h"
36
37
38#define LOG(kind,...) GNUNET_log_from (kind, "gnsrecord",__VA_ARGS__)
39
40
41/**
42 * Derive session key and iv from label and public key.
43 *
44 * @param iv initialization vector to initialize
45 * @param skey session key to initialize
46 * @param label label to use for KDF
47 * @param pub public key to use for KDF
48 */
49static void
50derive_block_aes_key (struct GNUNET_CRYPTO_SymmetricInitializationVector *iv,
51 struct GNUNET_CRYPTO_SymmetricSessionKey *skey,
52 const char *label,
53 const struct GNUNET_CRYPTO_EcdsaPublicKey *pub)
54{
55 static const char ctx_key[] = "gns-aes-ctx-key";
56 static const char ctx_iv[] = "gns-aes-ctx-iv";
57
58 GNUNET_CRYPTO_kdf (skey, sizeof (struct GNUNET_CRYPTO_SymmetricSessionKey),
59 pub, sizeof (struct GNUNET_CRYPTO_EcdsaPublicKey),
60 label, strlen (label),
61 ctx_key, strlen (ctx_key),
62 NULL, 0);
63 GNUNET_CRYPTO_kdf (iv, sizeof (struct GNUNET_CRYPTO_SymmetricInitializationVector),
64 pub, sizeof (struct GNUNET_CRYPTO_EcdsaPublicKey),
65 label, strlen (label),
66 ctx_iv, strlen (ctx_iv),
67 NULL, 0);
68}
69
70
71/**
72 * Sign name and records
73 *
74 * @param key the private key
75 * @param expire block expiration
76 * @param label the name for the records
77 * @param rd record data
78 * @param rd_count number of records
79 * @return NULL on error (block too large)
80 */
81struct GNUNET_NAMESTORE_Block *
82GNUNET_NAMESTORE_block_create (const struct GNUNET_CRYPTO_EcdsaPrivateKey *key,
83 struct GNUNET_TIME_Absolute expire,
84 const char *label,
85 const struct GNUNET_NAMESTORE_RecordData *rd,
86 unsigned int rd_count)
87{
88 size_t payload_len = GNUNET_NAMESTORE_records_get_size (rd_count, rd);
89 char payload[sizeof (uint32_t) + payload_len];
90 struct GNUNET_NAMESTORE_Block *block;
91 struct GNUNET_CRYPTO_EcdsaPublicKey pkey;
92 struct GNUNET_CRYPTO_EcdsaPrivateKey *dkey;
93 struct GNUNET_CRYPTO_SymmetricInitializationVector iv;
94 struct GNUNET_CRYPTO_SymmetricSessionKey skey;
95 uint32_t rd_count_nbo;
96
97 if (payload_len > GNUNET_NAMESTORE_MAX_VALUE_SIZE)
98 return NULL;
99 rd_count_nbo = htonl (rd_count);
100 memcpy (payload, &rd_count_nbo, sizeof (uint32_t));
101 GNUNET_assert (payload_len ==
102 GNUNET_NAMESTORE_records_serialize (rd_count, rd,
103 payload_len, &payload[sizeof (uint32_t)]));
104 block = GNUNET_malloc (sizeof (struct GNUNET_NAMESTORE_Block) +
105 sizeof (uint32_t) + payload_len);
106 block->purpose.size = htonl (sizeof (uint32_t) + payload_len +
107 sizeof (struct GNUNET_CRYPTO_EccSignaturePurpose) +
108 sizeof (struct GNUNET_TIME_AbsoluteNBO));
109 block->purpose.purpose = htonl (GNUNET_SIGNATURE_PURPOSE_GNS_RECORD_SIGN);
110 block->expiration_time = GNUNET_TIME_absolute_hton (expire);
111 dkey = GNUNET_CRYPTO_ecdsa_private_key_derive (key,
112 label,
113 "gns");
114 GNUNET_CRYPTO_ecdsa_key_get_public (dkey,
115 &block->derived_key);
116 GNUNET_CRYPTO_ecdsa_key_get_public (key,
117 &pkey);
118 derive_block_aes_key (&iv, &skey, label, &pkey);
119 GNUNET_break (payload_len + sizeof (uint32_t) ==
120 GNUNET_CRYPTO_symmetric_encrypt (payload, payload_len + sizeof (uint32_t),
121 &skey, &iv,
122 &block[1]));
123 if (GNUNET_OK !=
124 GNUNET_CRYPTO_ecdsa_sign (dkey,
125 &block->purpose,
126 &block->signature))
127 {
128 GNUNET_break (0);
129 GNUNET_free (dkey);
130 GNUNET_free (block);
131 return NULL;
132 }
133 GNUNET_free (dkey);
134 return block;
135}
136
137
138/**
139 * Check if a signature is valid. This API is used by the GNS Block
140 * to validate signatures received from the network.
141 *
142 * @param block block to verify
143 * @return #GNUNET_OK if the signature is valid
144 */
145int
146GNUNET_NAMESTORE_block_verify (const struct GNUNET_NAMESTORE_Block *block)
147{
148 return GNUNET_CRYPTO_ecdsa_verify (GNUNET_SIGNATURE_PURPOSE_GNS_RECORD_SIGN,
149 &block->purpose,
150 &block->signature,
151 &block->derived_key);
152}
153
154
155/**
156 * Decrypt block.
157 *
158 * @param block block to decrypt
159 * @param zone_key public key of the zone
160 * @param label the name for the records
161 * @param proc function to call with the result
162 * @param proc_cls closure for proc
163 * @return #GNUNET_OK on success, #GNUNET_SYSERR if the block was
164 * not well-formed
165 */
166int
167GNUNET_NAMESTORE_block_decrypt (const struct GNUNET_NAMESTORE_Block *block,
168 const struct GNUNET_CRYPTO_EcdsaPublicKey *zone_key,
169 const char *label,
170 GNUNET_NAMESTORE_RecordCallback proc,
171 void *proc_cls)
172{
173 size_t payload_len = ntohl (block->purpose.size) -
174 sizeof (struct GNUNET_CRYPTO_EccSignaturePurpose) -
175 sizeof (struct GNUNET_TIME_AbsoluteNBO);
176 struct GNUNET_CRYPTO_SymmetricInitializationVector iv;
177 struct GNUNET_CRYPTO_SymmetricSessionKey skey;
178
179 if (ntohl (block->purpose.size) <
180 sizeof (struct GNUNET_CRYPTO_EccSignaturePurpose) +
181 sizeof (struct GNUNET_TIME_AbsoluteNBO))
182 {
183 GNUNET_break_op (0);
184 return GNUNET_SYSERR;
185 }
186 derive_block_aes_key (&iv, &skey, label, zone_key);
187 {
188 char payload[payload_len];
189 uint32_t rd_count;
190
191 GNUNET_break (payload_len ==
192 GNUNET_CRYPTO_symmetric_decrypt (&block[1], payload_len,
193 &skey, &iv,
194 payload));
195 memcpy (&rd_count,
196 payload,
197 sizeof (uint32_t));
198 rd_count = ntohl (rd_count);
199 if (rd_count > 2048)
200 {
201 /* limit to sane value */
202 GNUNET_break_op (0);
203 return GNUNET_SYSERR;
204 }
205 {
206 struct GNUNET_NAMESTORE_RecordData rd[rd_count];
207
208 if (GNUNET_OK !=
209 GNUNET_NAMESTORE_records_deserialize (payload_len - sizeof (uint32_t),
210 &payload[sizeof (uint32_t)],
211 rd_count,
212 rd))
213 {
214 GNUNET_break_op (0);
215 return GNUNET_SYSERR;
216 }
217 if (NULL != proc)
218 proc (proc_cls, rd_count, (0 != rd_count) ? rd : NULL);
219 }
220 }
221 return GNUNET_OK;
222}
223
224
225/**
226 * Calculate the DHT query for a given @a label in a given @a zone.
227 *
228 * @param zone private key of the zone
229 * @param label label of the record
230 * @param query hash to use for the query
231 */
232void
233GNUNET_NAMESTORE_query_from_private_key (const struct GNUNET_CRYPTO_EcdsaPrivateKey *zone,
234 const char *label,
235 struct GNUNET_HashCode *query)
236{
237 struct GNUNET_CRYPTO_EcdsaPublicKey pub;
238
239 GNUNET_CRYPTO_ecdsa_key_get_public (zone, &pub);
240 GNUNET_NAMESTORE_query_from_public_key (&pub, label, query);
241}
242
243
244/**
245 * Calculate the DHT query for a given @a label in a given @a zone.
246 *
247 * @param pub public key of the zone
248 * @param label label of the record
249 * @param query hash to use for the query
250 */
251void
252GNUNET_NAMESTORE_query_from_public_key (const struct GNUNET_CRYPTO_EcdsaPublicKey *pub,
253 const char *label,
254 struct GNUNET_HashCode *query)
255{
256 struct GNUNET_CRYPTO_EcdsaPublicKey pd;
257
258 GNUNET_CRYPTO_ecdsa_public_key_derive (pub, label, "gns", &pd);
259 GNUNET_CRYPTO_hash (&pd, sizeof (pd), query);
260}
261
262
263/* end of gnsrecord_crypto.c */
diff --git a/src/gnsrecord/gnsrecord_misc.c b/src/gnsrecord/gnsrecord_misc.c
new file mode 100644
index 000000000..7d73af376
--- /dev/null
+++ b/src/gnsrecord/gnsrecord_misc.c
@@ -0,0 +1,267 @@
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 gnsrecord/gnsrecord_misc.c
23 * @brief MISC functions related to GNS records
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_gnsrecord_lib.h"
34#include "gnunet_dnsparser_lib.h"
35#include "gnunet_tun_lib.h"
36
37
38#define LOG(kind,...) GNUNET_log_from (kind, "gnsrecord",__VA_ARGS__)
39
40/**
41 * Convert a UTF-8 string to UTF-8 lowercase
42 * @param src source string
43 * @return converted result
44 */
45char *
46GNUNET_NAMESTORE_normalize_string (const char *src)
47{
48 GNUNET_assert (NULL != src);
49 char *res = strdup (src);
50 /* normalize */
51 GNUNET_STRINGS_utf8_tolower(src, &res);
52 return res;
53}
54
55
56/**
57 * Convert a zone key to a string (for printing debug messages).
58 * This is one of the very few calls in the entire API that is
59 * NOT reentrant!
60 *
61 * @param z the zone key
62 * @return string form; will be overwritten by next call to #GNUNET_NAMESTORE_z2s
63 */
64const char *
65GNUNET_NAMESTORE_z2s (const struct GNUNET_CRYPTO_EcdsaPublicKey *z)
66{
67 static char buf[sizeof (struct GNUNET_CRYPTO_EcdsaPublicKey) * 8];
68 char *end;
69
70 end = GNUNET_STRINGS_data_to_string ((const unsigned char *) z,
71 sizeof (struct GNUNET_CRYPTO_EcdsaPublicKey),
72 buf, sizeof (buf));
73 if (NULL == end)
74 {
75 GNUNET_break (0);
76 return NULL;
77 }
78 *end = '\0';
79 return buf;
80}
81
82
83/**
84 * Compares if two records are equal (ignoring flags such
85 * as authority, private and pending, but not relative vs.
86 * absolute expiration time).
87 *
88 * @param a record
89 * @param b record
90 * @return #GNUNET_YES if the records are equal or #GNUNET_NO if they are not
91 */
92int
93GNUNET_NAMESTORE_records_cmp (const struct GNUNET_NAMESTORE_RecordData *a,
94 const struct GNUNET_NAMESTORE_RecordData *b)
95{
96 LOG (GNUNET_ERROR_TYPE_DEBUG,
97 "Comparing records\n");
98 if (a->record_type != b->record_type)
99 {
100 LOG (GNUNET_ERROR_TYPE_DEBUG,
101 "Record type %lu != %lu\n", a->record_type, b->record_type);
102 return GNUNET_NO;
103 }
104 if ((a->expiration_time != b->expiration_time) &&
105 ((a->expiration_time != 0) && (b->expiration_time != 0)))
106 {
107 LOG (GNUNET_ERROR_TYPE_DEBUG,
108 "Expiration time %llu != %llu\n",
109 a->expiration_time,
110 b->expiration_time);
111 return GNUNET_NO;
112 }
113 if ((a->flags & GNUNET_NAMESTORE_RF_RCMP_FLAGS)
114 != (b->flags & GNUNET_NAMESTORE_RF_RCMP_FLAGS))
115 {
116 LOG (GNUNET_ERROR_TYPE_DEBUG,
117 "Flags %lu (%lu) != %lu (%lu)\n", a->flags,
118 a->flags & GNUNET_NAMESTORE_RF_RCMP_FLAGS, b->flags,
119 b->flags & GNUNET_NAMESTORE_RF_RCMP_FLAGS);
120 return GNUNET_NO;
121 }
122 if (a->data_size != b->data_size)
123 {
124 LOG (GNUNET_ERROR_TYPE_DEBUG,
125 "Data size %lu != %lu\n",
126 a->data_size,
127 b->data_size);
128 return GNUNET_NO;
129 }
130 if (0 != memcmp (a->data, b->data, a->data_size))
131 {
132 LOG (GNUNET_ERROR_TYPE_DEBUG,
133 "Data contents do not match\n");
134 return GNUNET_NO;
135 }
136 LOG (GNUNET_ERROR_TYPE_DEBUG,
137 "Records are equal\n");
138 return GNUNET_YES;
139}
140
141
142/**
143 * Returns the expiration time of the given block of records. The block
144 * expiration time is the expiration time of the record with smallest
145 * expiration time.
146 *
147 * @param rd_count number of records given in @a rd
148 * @param rd array of records
149 * @return absolute expiration time
150 */
151struct GNUNET_TIME_Absolute
152GNUNET_NAMESTORE_record_get_expiration_time (unsigned int rd_count,
153 const struct GNUNET_NAMESTORE_RecordData *rd)
154{
155 unsigned int c;
156 struct GNUNET_TIME_Absolute expire;
157 struct GNUNET_TIME_Absolute at;
158 struct GNUNET_TIME_Relative rt;
159
160 if (NULL == rd)
161 return GNUNET_TIME_UNIT_ZERO_ABS;
162 expire = GNUNET_TIME_UNIT_FOREVER_ABS;
163 for (c = 0; c < rd_count; c++)
164 {
165 if (0 != (rd[c].flags & GNUNET_NAMESTORE_RF_RELATIVE_EXPIRATION))
166 {
167 rt.rel_value_us = rd[c].expiration_time;
168 at = GNUNET_TIME_relative_to_absolute (rt);
169 }
170 else
171 {
172 at.abs_value_us = rd[c].expiration_time;
173 }
174 expire = GNUNET_TIME_absolute_min (at, expire);
175 }
176 LOG (GNUNET_ERROR_TYPE_DEBUG,
177 "Determined expiration time for block with %u records to be %s\n",
178 rd_count,
179 GNUNET_STRINGS_absolute_time_to_string (expire));
180 return expire;
181}
182
183
184/**
185 * Test if a given record is expired.
186 *
187 * @return #GNUNET_YES if the record is expired,
188 * #GNUNET_NO if not
189 */
190int
191GNUNET_NAMESTORE_is_expired (const struct GNUNET_NAMESTORE_RecordData *rd)
192{
193 struct GNUNET_TIME_Absolute at;
194
195 if (0 != (rd->flags & GNUNET_NAMESTORE_RF_RELATIVE_EXPIRATION))
196 return GNUNET_NO;
197 at.abs_value_us = rd->expiration_time;
198 return (0 == GNUNET_TIME_absolute_get_remaining (at).rel_value_us) ? GNUNET_YES : GNUNET_NO;
199}
200
201
202/**
203 * Convert public key to the respective absolute domain name in the
204 * ".zkey" pTLD.
205 * This is one of the very few calls in the entire API that is
206 * NOT reentrant!
207 *
208 * @param pkey a public key with a point on the eliptic curve
209 * @return string "X.zkey" where X is the public
210 * key in an encoding suitable for DNS labels.
211 */
212const char *
213GNUNET_NAMESTORE_pkey_to_zkey (const struct GNUNET_CRYPTO_EcdsaPublicKey *pkey)
214{
215 static char ret[128];
216 char *pkeys;
217
218 pkeys = GNUNET_CRYPTO_ecdsa_public_key_to_string (pkey);
219 GNUNET_snprintf (ret,
220 sizeof (ret),
221 "%s.zkey",
222 pkeys);
223 GNUNET_free (pkeys);
224 return ret;
225}
226
227
228/**
229 * Convert an absolute domain name in the ".zkey" pTLD to the
230 * respective public key.
231 *
232 * @param zkey string "X.zkey" where X is the coordinates of the public
233 * key in an encoding suitable for DNS labels.
234 * @param pkey set to a public key on the eliptic curve
235 * @return #GNUNET_SYSERR if @a zkey has the wrong syntax
236 */
237int
238GNUNET_NAMESTORE_zkey_to_pkey (const char *zkey,
239 struct GNUNET_CRYPTO_EcdsaPublicKey *pkey)
240{
241 char *cpy;
242 char *dot;
243 const char *x;
244
245 cpy = GNUNET_strdup (zkey);
246 x = cpy;
247 if (NULL == (dot = strchr (x, (int) '.')))
248 goto error;
249 *dot = '\0';
250 if (0 != strcasecmp (dot + 1,
251 "zkey"))
252 goto error;
253
254 if (GNUNET_OK !=
255 GNUNET_CRYPTO_ecdsa_public_key_from_string (x,
256 strlen (x),
257 pkey))
258 goto error;
259 GNUNET_free (cpy);
260 return GNUNET_OK;
261 error:
262 GNUNET_free (cpy);
263 return GNUNET_SYSERR;
264}
265
266
267/* end of gnsrecord_misc.c */
diff --git a/src/gnsrecord/gnsrecord_serialization.c b/src/gnsrecord/gnsrecord_serialization.c
new file mode 100644
index 000000000..0fd10b3e0
--- /dev/null
+++ b/src/gnsrecord/gnsrecord_serialization.c
@@ -0,0 +1,188 @@
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 gnsrecord/gnsrecord_serialization.c
23 * @brief API to serialize and deserialize GNS records
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_gnsrecord_lib.h"
34#include "gnunet_dnsparser_lib.h"
35#include "gnunet_tun_lib.h"
36
37
38#define LOG(kind,...) GNUNET_log_from (kind, "gnsrecord",__VA_ARGS__)
39
40GNUNET_NETWORK_STRUCT_BEGIN
41
42
43/**
44 * Internal format of a record in the serialized form.
45 */
46struct NetworkRecord
47{
48
49 /**
50 * Expiration time for the DNS record; relative or absolute depends
51 * on 'flags', network byte order.
52 */
53 uint64_t expiration_time GNUNET_PACKED;
54
55 /**
56 * Number of bytes in 'data', network byte order.
57 */
58 uint32_t data_size GNUNET_PACKED;
59
60 /**
61 * Type of the GNS/DNS record, network byte order.
62 */
63 uint32_t record_type GNUNET_PACKED;
64
65 /**
66 * Flags for the record, network byte order.
67 */
68 uint32_t flags GNUNET_PACKED;
69
70};
71
72GNUNET_NETWORK_STRUCT_END
73
74
75/**
76 * Calculate how many bytes we will need to serialize the given
77 * records.
78 *
79 * @param rd_count number of records in the rd array
80 * @param rd array of #GNUNET_NAMESTORE_RecordData with @a rd_count elements
81 * @return the required size to serialize
82 */
83size_t
84GNUNET_NAMESTORE_records_get_size (unsigned int rd_count,
85 const struct GNUNET_NAMESTORE_RecordData *rd)
86{
87 unsigned int i;
88 size_t ret;
89
90 ret = sizeof (struct NetworkRecord) * rd_count;
91 for (i=0;i<rd_count;i++)
92 {
93 GNUNET_assert ((ret + rd[i].data_size) >= ret);
94 ret += rd[i].data_size;
95 }
96 return ret;
97}
98
99
100/**
101 * Serialize the given records to the given destination buffer.
102 *
103 * @param rd_count number of records in the rd array
104 * @param rd array of #GNUNET_NAMESTORE_RecordData with @a rd_count elements
105 * @param dest_size size of the destination array
106 * @param dest where to write the result
107 * @return the size of serialized records, -1 if records do not fit
108 */
109ssize_t
110GNUNET_NAMESTORE_records_serialize (unsigned int rd_count,
111 const struct GNUNET_NAMESTORE_RecordData *rd,
112 size_t dest_size,
113 char *dest)
114{
115 struct NetworkRecord rec;
116 unsigned int i;
117 size_t off;
118
119 off = 0;
120 for (i=0;i<rd_count;i++)
121 {
122 LOG (GNUNET_ERROR_TYPE_DEBUG,
123 "Serializing record %u with flags %d and expiration time %llu\n",
124 i,
125 rd[i].flags,
126 (unsigned long long) rd[i].expiration_time);
127 rec.expiration_time = GNUNET_htonll (rd[i].expiration_time);
128 rec.data_size = htonl ((uint32_t) rd[i].data_size);
129 rec.record_type = htonl (rd[i].record_type);
130 rec.flags = htonl (rd[i].flags);
131 if (off + sizeof (rec) > dest_size)
132 return -1;
133 memcpy (&dest[off], &rec, sizeof (rec));
134 off += sizeof (rec);
135 if (off + rd[i].data_size > dest_size)
136 return -1;
137 memcpy (&dest[off], rd[i].data, rd[i].data_size);
138 off += rd[i].data_size;
139 }
140 return off;
141}
142
143
144/**
145 * Deserialize the given records to the given destination.
146 *
147 * @param len size of the serialized record data
148 * @param src the serialized record data
149 * @param rd_count number of records in the rd array
150 * @param dest where to put the data
151 * @return #GNUNET_OK on success, #GNUNET_SYSERR on error
152 */
153int
154GNUNET_NAMESTORE_records_deserialize (size_t len,
155 const char *src,
156 unsigned int rd_count,
157 struct GNUNET_NAMESTORE_RecordData *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 if (off + sizeof (rec) > len)
167 return GNUNET_SYSERR;
168 memcpy (&rec, &src[off], sizeof (rec));
169 dest[i].expiration_time = GNUNET_ntohll (rec.expiration_time);
170 dest[i].data_size = ntohl ((uint32_t) rec.data_size);
171 dest[i].record_type = ntohl (rec.record_type);
172 dest[i].flags = ntohl (rec.flags);
173 off += sizeof (rec);
174 if (off + dest[i].data_size > len)
175 return GNUNET_SYSERR;
176 dest[i].data = &src[off];
177 off += dest[i].data_size;
178 LOG (GNUNET_ERROR_TYPE_DEBUG,
179 "Deserialized record %u with flags %d and expiration time %llu\n",
180 i,
181 dest[i].flags,
182 (unsigned long long) dest[i].expiration_time);
183 }
184 return GNUNET_OK;
185}
186
187
188/* end of gnsrecord_serialization.c */
diff --git a/src/gnsrecord/test_gnsrecord_crypto.c b/src/gnsrecord/test_gnsrecord_crypto.c
new file mode 100644
index 000000000..345bf353b
--- /dev/null
+++ b/src/gnsrecord/test_gnsrecord_crypto.c
@@ -0,0 +1,145 @@
1/*
2 This file is part of GNUnet.
3 (C) 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 * @file gnsrecord/test_gnsrecord_crypto.c
22 * @brief testcase for block creation, verification and decryption
23 */
24#include "platform.h"
25#include "gnunet_util_lib.h"
26#include "gnunet_gnsrecord_lib.h"
27
28#define RECORDS 5
29
30#define TEST_RECORD_TYPE 1234
31
32#define TEST_RECORD_DATALEN 123
33
34#define TEST_RECORD_DATA 'a'
35
36#define TEST_REMOVE_RECORD_TYPE 4321
37
38#define TEST_REMOVE_RECORD_DATALEN 255
39
40#define TEST_REMOVE_RECORD_DATA 'b'
41
42
43static struct GNUNET_CRYPTO_EcdsaPrivateKey * privkey;
44
45static struct GNUNET_NAMESTORE_RecordData *s_rd;
46
47static char *s_name;
48
49static int res;
50
51
52static struct GNUNET_NAMESTORE_RecordData *
53create_record (int count)
54{
55 unsigned int c;
56 struct GNUNET_NAMESTORE_RecordData * rd;
57
58 rd = GNUNET_malloc (count * sizeof (struct GNUNET_NAMESTORE_RecordData));
59 for (c = 0; c < count; c++)
60 {
61 rd[c].expiration_time = GNUNET_TIME_absolute_get().abs_value_us;
62 rd[c].record_type = TEST_RECORD_TYPE;
63 rd[c].data_size = TEST_RECORD_DATALEN;
64 rd[c].data = GNUNET_malloc(TEST_RECORD_DATALEN);
65 memset ((char *) rd[c].data, TEST_RECORD_DATA, TEST_RECORD_DATALEN);
66 }
67 return rd;
68}
69
70
71static void
72rd_decrypt_cb (void *cls,
73 unsigned int rd_count,
74 const struct GNUNET_NAMESTORE_RecordData *rd)
75{
76 char rd_cmp_data[TEST_RECORD_DATALEN];
77
78 int c;
79
80 GNUNET_assert (RECORDS == rd_count);
81 GNUNET_assert (NULL != rd);
82
83 memset (rd_cmp_data, 'a', TEST_RECORD_DATALEN);
84
85 for (c = 0; c < rd_count; c++)
86 {
87 GNUNET_assert (TEST_RECORD_TYPE == rd[c].record_type);
88 GNUNET_assert (TEST_RECORD_DATALEN == rd[c].data_size);
89 GNUNET_assert (0 == memcmp (&rd_cmp_data, rd[c].data, TEST_RECORD_DATALEN));
90 }
91 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
92 "Block was decrypted successfully \n");
93 res = 0;
94
95}
96
97static void
98run (void *cls, char *const *args, const char *cfgfile,
99 const struct GNUNET_CONFIGURATION_Handle *cfg)
100{
101 struct GNUNET_NAMESTORE_Block *block;
102 struct GNUNET_CRYPTO_EcdsaPublicKey pubkey;
103
104 /* load privat key */
105 char *hostkey_file;
106 GNUNET_asprintf(&hostkey_file,"zonefiles%s%s",DIR_SEPARATOR_STR,
107 "N0UJMP015AFUNR2BTNM3FKPBLG38913BL8IDMCO2H0A1LIB81960.zkey");
108 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Using zonekey file `%s' \n", hostkey_file);
109 privkey = GNUNET_CRYPTO_ecdsa_key_create_from_file(hostkey_file);
110 GNUNET_free (hostkey_file);
111 GNUNET_assert (privkey != NULL);
112 struct GNUNET_TIME_Absolute expire = GNUNET_TIME_absolute_get();
113 /* get public key */
114 GNUNET_CRYPTO_ecdsa_key_get_public(privkey, &pubkey);
115
116 /* create record */
117 s_name = "DUMMY.dummy.gnunet";
118 s_rd = create_record (RECORDS);
119
120 /* Create block */
121 GNUNET_assert (NULL != (block = GNUNET_NAMESTORE_block_create (privkey, expire,s_name, s_rd, RECORDS)));
122 GNUNET_assert (GNUNET_OK == GNUNET_NAMESTORE_block_verify (block));
123 GNUNET_assert (GNUNET_OK == GNUNET_NAMESTORE_block_decrypt (block, &pubkey, s_name, &rd_decrypt_cb, s_name));
124
125 GNUNET_free (block);
126}
127
128
129int
130main (int argc, char *argv[])
131{
132 static char *const argvx[] = { "test-gnsrecord-crypto",
133 NULL
134 };
135 static struct GNUNET_GETOPT_CommandLineOption options[] = {
136 GNUNET_GETOPT_OPTION_END
137 };
138
139 res = 1;
140 GNUNET_PROGRAM_run ((sizeof (argvx) / sizeof (char *)) - 1, argvx, "test-namestore-api",
141 "nohelp", options, &run, &res);
142 return res;
143}
144
145/* end of test_gnsrecord_crypto.c */
diff --git a/src/gnsrecord/test_gnsrecord_serialization.c b/src/gnsrecord/test_gnsrecord_serialization.c
new file mode 100644
index 000000000..de6a7ba1d
--- /dev/null
+++ b/src/gnsrecord/test_gnsrecord_serialization.c
@@ -0,0 +1,140 @@
1/*
2 This file is part of GNUnet.
3 (C) 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 * @file gnsrecord/test_gnsrecord_serialization.c
22 * @brief testcase for gnsrecord_serialization.c
23 */
24#include "platform.h"
25#include "gnunet_util_lib.h"
26#include "gnunet_gnsrecord_lib.h"
27
28#define TIMEOUT GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_SECONDS, 100)
29
30static int res;
31
32
33static void
34run (void *cls, char *const *args, const char *cfgfile,
35 const struct GNUNET_CONFIGURATION_Handle *cfg)
36{
37 size_t len;
38 int c;
39
40 int rd_count = 3;
41 size_t data_len;
42 struct GNUNET_NAMESTORE_RecordData src[rd_count];
43
44 memset(src, '\0', rd_count * sizeof (struct GNUNET_NAMESTORE_RecordData));
45
46 data_len = 0;
47 for (c = 0; c < rd_count; c++)
48 {
49 src[c].record_type = c+1;
50 src[c].data_size = data_len;
51 src[c].data = GNUNET_malloc (data_len);
52
53 /* Setting data to data_len * record_type */
54 memset ((char *) src[c].data, 'a', data_len);
55 data_len += 10;
56 }
57 res = 0;
58
59 len = GNUNET_NAMESTORE_records_get_size(rd_count, src);
60 char rd_ser[len];
61 GNUNET_assert (len == GNUNET_NAMESTORE_records_serialize(rd_count, src, len, rd_ser));
62
63 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Serialized data len: %u\n",len);
64
65 GNUNET_assert (rd_ser != NULL);
66
67 struct GNUNET_NAMESTORE_RecordData dst[rd_count];
68 GNUNET_assert (GNUNET_OK == GNUNET_NAMESTORE_records_deserialize (len, rd_ser, rd_count, dst));
69
70 GNUNET_assert (dst != NULL);
71
72 for (c = 0; c < rd_count; c++)
73 {
74 if (src[c].data_size != dst[c].data_size)
75 {
76 GNUNET_break (0);
77 res = 1;
78 }
79 if (src[c].expiration_time != dst[c].expiration_time)
80 {
81 GNUNET_break (0);
82 res = 1;
83 }
84 if (src[c].flags != dst[c].flags)
85 {
86 GNUNET_break (0);
87 res = 1;
88 }
89 if (src[c].record_type != dst[c].record_type)
90 {
91 GNUNET_break (0);
92 res = 1;
93 }
94
95 size_t data_size = src[c].data_size;
96 char data[data_size];
97 memset (data, 'a', data_size);
98 if (0 != memcmp (data, dst[c].data, data_size))
99 {
100 GNUNET_break (0);
101 res = 1;
102 }
103 if (0 != memcmp (data, src[c].data, data_size))
104 {
105 GNUNET_break (0);
106 res = 1;
107 }
108 if (0 != memcmp (src[c].data, dst[c].data, src[c].data_size))
109 {
110 GNUNET_break (0);
111 res = 1;
112 }
113
114 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Element [%i]: EQUAL\n", c);
115 }
116
117 for (c = 0; c < rd_count; c++)
118 {
119 GNUNET_free ((void *)src[c].data);
120 }
121}
122
123
124int
125main (int argcx, char *argvx[])
126{
127 static char *const argv[] = { "test_gnsrecord_serialization",
128 NULL
129 };
130 static struct GNUNET_GETOPT_CommandLineOption options[] = {
131 GNUNET_GETOPT_OPTION_END
132 };
133
134 res = 1;
135 GNUNET_PROGRAM_run ((sizeof (argv) / sizeof (char *)) - 1, argv, "test_namestore_record_serialization",
136 "nohelp", options, &run, &res);
137 return res;
138}
139
140/* end of test_gnsrecord_serialization.c */