aboutsummaryrefslogtreecommitdiff
path: root/src/hello/hello-uri.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/hello/hello-uri.c')
-rw-r--r--src/hello/hello-uri.c459
1 files changed, 406 insertions, 53 deletions
diff --git a/src/hello/hello-uri.c b/src/hello/hello-uri.c
index 347c4bf0c..49e4f6ed3 100644
--- a/src/hello/hello-uri.c
+++ b/src/hello/hello-uri.c
@@ -22,6 +22,17 @@
22 * @file hello/hello-uri.c 22 * @file hello/hello-uri.c
23 * @brief helper library for handling URI-based HELLOs 23 * @brief helper library for handling URI-based HELLOs
24 * @author Christian Grothoff 24 * @author Christian Grothoff
25 *
26 * Note:
27 * - Current API does not support deserializing HELLO of
28 * another peer and then serializing it into another
29 * format (we always require the private key).
30 * Not sure if we need this, but if we do, we need
31 * to extend the builder and the API.
32 * - Current API does not allow overriding the default
33 * HELLO expiration time. We may want to add a function
34 * that does this to create bootstrap HELLOs shipped with
35 * the TGZ.
25 */ 36 */
26#include "platform.h" 37#include "platform.h"
27#include "gnunet_signatures.h" 38#include "gnunet_signatures.h"
@@ -29,15 +40,44 @@
29#include "gnunet_protocols.h" 40#include "gnunet_protocols.h"
30#include "gnunet_util_lib.h" 41#include "gnunet_util_lib.h"
31 42
43/**
44 * For how long are HELLO signatures valid?
45 */
46#define HELLO_ADDRESS_EXPIRATION GNUNET_TIME_relative_multiply ( \
47 GNUNET_TIME_UNIT_DAYS, 2)
48
49
32GNUNET_NETWORK_STRUCT_BEGIN 50GNUNET_NETWORK_STRUCT_BEGIN
33 51
34/** 52/**
53 * Message signed as part of a HELLO block/URL.
54 */
55struct HelloSignaturePurpose
56{
57 /**
58 * Purpose must be #GNUNET_SIGNATURE_PURPOSE_HELLO
59 */
60 struct GNUNET_CRYPTO_EccSignaturePurpose purpose;
61
62 /**
63 * When does the signature expire?
64 */
65 struct GNUNET_TIME_AbsoluteNBO expiration_time;
66
67 /**
68 * Hash over all addresses.
69 */
70 struct GNUNET_HashCode h_addrs;
71
72};
73
74/**
35 * Binary block we sign when we sign an address. 75 * Binary block we sign when we sign an address.
36 */ 76 */
37struct HelloUriMessage 77struct HelloUriMessage
38{ 78{
39 /** 79 /**
40 * Purpose must be #GNUNET_MESSAGE_TYPE_HELLO_URI 80 * Type must be #GNUNET_MESSAGE_TYPE_HELLO_URI
41 */ 81 */
42 struct GNUNET_MessageHeader header; 82 struct GNUNET_MessageHeader header;
43 83
@@ -51,11 +91,32 @@ struct HelloUriMessage
51 */ 91 */
52 uint16_t url_counter GNUNET_PACKED; 92 uint16_t url_counter GNUNET_PACKED;
53 93
94 /* followed by a 'block' */
95};
96
97
98/**
99 * Start of a 'block'.
100 */
101struct BlockHeader
102{
54 /** 103 /**
55 * Public key of the peer. 104 * Public key of the peer.
56 */ 105 */
57 struct GNUNET_PeerIdentity pid; 106 struct GNUNET_PeerIdentity pid;
107
108 /**
109 * Signature over the block, of purpose #GNUNET_SIGNATURE_PURPOSE_HELLO.
110 */
111 struct GNUNET_CRYPTO_EddsaSignature sig;
112
113 /**
114 * When does the HELLO expire?
115 */
116 struct GNUNET_TIME_AbsoluteNBO expiration_time;
117
58}; 118};
119
59GNUNET_NETWORK_STRUCT_END 120GNUNET_NETWORK_STRUCT_END
60 121
61 122
@@ -114,6 +175,98 @@ struct GNUNET_HELLO_Builder
114}; 175};
115 176
116 177
178/**
179 * Compute @a hash over addresses in @a builder.
180 *
181 * @param builder the builder to hash addresses of
182 * @param[out] hash where to write the hash
183 */
184static void
185hash_addresses (const struct GNUNET_HELLO_Builder *builder,
186 struct GNUNET_HashCode *hash)
187{
188 struct GNUNET_HashContext *hc;
189
190 hc = GNUNET_CRYPTO_hash_context_start ();
191 for (struct Address *a = builder->a_head;
192 NULL != a;
193 a = a->next)
194 {
195 GNUNET_CRYPTO_hash_context_read (hc,
196 a->uri,
197 a->uri_len);
198 }
199 GNUNET_CRYPTO_hash_context_finish (hc,
200 hash);
201
202}
203
204
205/**
206 * Create HELLO signature.
207 *
208 * @param builder the builder to use
209 * @param et expiration time to sign
210 * @param priv key to sign with
211 * @param[out] sig where to write the signature
212 */
213static void
214sign_hello (const struct GNUNET_HELLO_Builder *builder,
215 struct GNUNET_TIME_Timestamp et,
216 const struct GNUNET_CRYPTO_EddsaPrivateKey *priv,
217 struct GNUNET_CRYPTO_EddsaSignature *sig)
218{
219 struct HelloSignaturePurpose hsp = {
220 .purpose.size = htonl (sizeof (hsp)),
221 .purpose.purpose = htonl (GNUNET_SIGNATURE_PURPOSE_HELLO),
222 .expiration_time = GNUNET_TIME_absolute_hton (et.abs_time)
223 };
224
225 hash_addresses (builder,
226 &hsp.h_addrs);
227 GNUNET_CRYPTO_eddsa_sign (priv,
228 &hsp,
229 sig);
230}
231
232
233/**
234 * Verify HELLO signature.
235 *
236 * @param builder the builder to use
237 * @param et expiration time to verify
238 * @param sig signature to verify
239 * @return #GNUNET_OK if everything is ok, #GNUNET_NO if the
240 * HELLO expired, #GNUNET_SYSERR if the signature is wrong
241 */
242static enum GNUNET_GenericReturnValue
243verify_hello (const struct GNUNET_HELLO_Builder *builder,
244 struct GNUNET_TIME_Absolute et,
245 const struct GNUNET_CRYPTO_EddsaSignature *sig)
246{
247 struct HelloSignaturePurpose hsp = {
248 .purpose.size = htonl (sizeof (hsp)),
249 .purpose.purpose = htonl (GNUNET_SIGNATURE_PURPOSE_HELLO),
250 .expiration_time = GNUNET_TIME_absolute_hton (et)
251 };
252
253 hash_addresses (builder,
254 &hsp.h_addrs);
255 if (GNUNET_OK !=
256 GNUNET_CRYPTO_eddsa_verify (GNUNET_SIGNATURE_PURPOSE_HELLO,
257 &hsp,
258 sig,
259 &builder->pid.public_key))
260 {
261 GNUNET_break_op (0);
262 return GNUNET_SYSERR;
263 }
264 if (GNUNET_TIME_absolute_is_past (et))
265 return GNUNET_NO;
266 return GNUNET_OK;
267}
268
269
117struct GNUNET_HELLO_Builder * 270struct GNUNET_HELLO_Builder *
118GNUNET_HELLO_builder_new (const struct GNUNET_PeerIdentity *pid) 271GNUNET_HELLO_builder_new (const struct GNUNET_PeerIdentity *pid)
119{ 272{
@@ -147,29 +300,45 @@ struct GNUNET_HELLO_Builder *
147GNUNET_HELLO_builder_from_msg (const struct GNUNET_MessageHeader *msg) 300GNUNET_HELLO_builder_from_msg (const struct GNUNET_MessageHeader *msg)
148{ 301{
149 const struct HelloUriMessage *h; 302 const struct HelloUriMessage *h;
150 struct GNUNET_HELLO_Builder *b;
151 uint16_t size = ntohs (msg->size); 303 uint16_t size = ntohs (msg->size);
152 const char *pos;
153 304
154 if (GNUNET_MESSAGE_TYPE_HELLO_URI != ntohs (msg->type)) 305 if (GNUNET_MESSAGE_TYPE_HELLO_URI != ntohs (msg->type))
155 { 306 {
156 GNUNET_break (0); 307 GNUNET_break (0);
157 return NULL; 308 return NULL;
158 } 309 }
159 if (sizeof (struct HelloUriMessage) < size) 310 if (sizeof (struct HelloUriMessage) > size)
160 { 311 {
161 GNUNET_break_op (0); 312 GNUNET_break_op (0);
162 return NULL; 313 return NULL;
163 } 314 }
164 h = (const struct HelloUriMessage *) msg; 315 h = (const struct HelloUriMessage *) msg;
165 pos = (const char *) &h[1];
166 size -= sizeof (*h); 316 size -= sizeof (*h);
167 b = GNUNET_HELLO_builder_new (&h->pid); 317 return GNUNET_HELLO_builder_from_block (&h[1],
168 for (unsigned int i = 0; i<ntohs (h->url_counter); i++) 318 size);
319}
320
321
322struct GNUNET_HELLO_Builder *
323GNUNET_HELLO_builder_from_block (const void *block,
324 size_t block_size)
325{
326 const struct BlockHeader *bh = block;
327 struct GNUNET_HELLO_Builder *b;
328
329 if (block_size < sizeof (*bh))
169 { 330 {
170 const char *end = memchr (pos, 331 GNUNET_break_op (0);
332 return NULL;
333 }
334 b = GNUNET_HELLO_builder_new (&bh->pid);
335 block += sizeof (*bh);
336 block_size -= sizeof (*bh);
337 while (block_size > 0)
338 {
339 const void *end = memchr (block,
171 '\0', 340 '\0',
172 size); 341 block_size);
173 342
174 if (NULL == end) 343 if (NULL == end)
175 { 344 {
@@ -179,79 +348,174 @@ GNUNET_HELLO_builder_from_msg (const struct GNUNET_MessageHeader *msg)
179 } 348 }
180 if (GNUNET_OK != 349 if (GNUNET_OK !=
181 GNUNET_HELLO_builder_add_address (b, 350 GNUNET_HELLO_builder_add_address (b,
182 pos)) 351 block))
183 { 352 {
184 GNUNET_break_op (0); 353 GNUNET_break_op (0);
185 GNUNET_HELLO_builder_free (b); 354 GNUNET_HELLO_builder_free (b);
186 return NULL; 355 return NULL;
187 } 356 }
188 end++; /* skip '\0' */ 357 end++;
189 size -= (end - pos); 358 block_size -= (end - block);
190 pos = end; 359 block = end;
191 } 360 }
192 if (0 != size)
193 { 361 {
194 GNUNET_break_op (0); 362 enum GNUNET_GenericReturnValue ret;
195 GNUNET_HELLO_builder_free (b); 363
196 return NULL; 364 ret = verify_hello (b,
365 GNUNET_TIME_absolute_ntoh (bh->expiration_time),
366 &bh->sig);
367 GNUNET_break (GNUNET_SYSERR != ret);
368 if (GNUNET_OK != ret)
369 {
370 GNUNET_HELLO_builder_free (b);
371 return NULL;
372 }
197 } 373 }
198 return b; 374 return b;
199} 375}
200 376
201 377
202struct GNUNET_HELLO_Builder * 378struct GNUNET_HELLO_Builder *
203GNUNET_HELLO_builder_from_block (const void *block, 379GNUNET_HELLO_builder_from_url (const char *url)
204 size_t block_size)
205{ 380{
206 const struct GNUNET_PeerIdentity *pid = block; 381 const char *q;
382 const char *s1;
383 const char *s2;
384 struct GNUNET_PeerIdentity pid;
385 struct GNUNET_CRYPTO_EddsaSignature sig;
386 struct GNUNET_TIME_Absolute et;
387 size_t len;
207 struct GNUNET_HELLO_Builder *b; 388 struct GNUNET_HELLO_Builder *b;
208 389
209 if (block_size < sizeof (*pid)) 390 if (0 != strncasecmp (url,
391 "gnunet://hello/",
392 strlen ("gnunet://hello/")))
393 return NULL;
394 url += strlen ("gnunet://hello/");
395 s1 = strchr (url, '/');
396 if (NULL == s1)
210 { 397 {
211 GNUNET_break_op (0); 398 GNUNET_break_op (0);
212 return NULL; 399 return NULL;
213 } 400 }
214 b = GNUNET_HELLO_builder_new (pid); 401 s2 = strchr (s1 + 1, '/');
215 block += sizeof (*pid); 402 if (NULL == s1)
216 block_size -= sizeof (*pid);
217 while (block_size > 0)
218 { 403 {
219 const void *end = memchr (block, 404 GNUNET_break_op (0);
220 '\0', 405 return NULL;
221 block_size); 406 }
407 q = strchr (url, '?');
408 if (NULL == q)
409 q = url + strlen (url);
410 if (GNUNET_OK !=
411 GNUNET_STRINGS_string_to_data (url,
412 s1 - url,
413 &pid,
414 sizeof(pid)))
415 {
416 GNUNET_break_op (0);
417 return NULL;
418 }
419 if (GNUNET_OK !=
420 GNUNET_STRINGS_string_to_data (s1 + 1,
421 s2 - (s1 + 1),
422 &sig,
423 sizeof(sig)))
424 {
425 GNUNET_break_op (0);
426 return NULL;
427 }
428 {
429 unsigned long long sec;
430 char dummy = '?';
431
432 if ( (0 == sscanf (s2 + 1,
433 "%llu%c",
434 &sec,
435 &dummy)) ||
436 ('?' != dummy) )
437 {
438 GNUNET_break_op (0);
439 return NULL;
440 }
441 et = GNUNET_TIME_absolute_from_s (sec);
442 }
222 443
223 if (NULL == end) 444 b = GNUNET_HELLO_builder_new (&pid);
445 len = strlen (q);
446 while (len > 0)
447 {
448 const char *eq;
449 const char *amp;
450 char *addr = NULL;
451 char *uri;
452
453 /* skip ?/& separator */
454 len--;
455 q++;
456 eq = strchr (q, '=');
457 if ( (eq == q) ||
458 (NULL == eq) )
224 { 459 {
225 GNUNET_break_op (0); 460 GNUNET_break_op (0);
226 GNUNET_HELLO_builder_free (b); 461 GNUNET_HELLO_builder_free (b);
227 return NULL; 462 return NULL;
228 } 463 }
464 amp = strchr (eq, '&');
465 if (NULL == amp)
466 amp = &q[len];
467 GNUNET_STRINGS_urldecode (eq + 1,
468 amp - (eq + 1),
469 &addr);
470 if ( (NULL == addr) ||
471 (0 == strlen (addr)) )
472 {
473 GNUNET_free (addr);
474 GNUNET_break_op (0);
475 GNUNET_HELLO_builder_free (b);
476 return NULL;
477 }
478 GNUNET_asprintf (&uri,
479 "%.*s://%s",
480 (int) (eq - q),
481 q,
482 addr);
483 GNUNET_free (addr);
229 if (GNUNET_OK != 484 if (GNUNET_OK !=
230 GNUNET_HELLO_builder_add_address (b, 485 GNUNET_HELLO_builder_add_address (b,
231 block)) 486 uri))
232 { 487 {
233 GNUNET_break_op (0); 488 GNUNET_break_op (0);
489 GNUNET_free (uri);
234 GNUNET_HELLO_builder_free (b); 490 GNUNET_HELLO_builder_free (b);
235 return NULL; 491 return NULL;
236 } 492 }
237 end++; 493 GNUNET_free (uri);
238 block_size -= (end - block); 494 /* move to next URL */
239 block = end; 495 len -= (amp - q);
496 q = amp;
240 } 497 }
241 return b;
242}
243 498
499 {
500 enum GNUNET_GenericReturnValue ret;
244 501
245struct GNUNET_HELLO_Builder * 502 ret = verify_hello (b,
246GNUNET_HELLO_builder_from_url (const char *url) 503 et,
247{ 504 &sig);
248 // FIXME! 505 GNUNET_break (GNUNET_SYSERR != ret);
249 return NULL; 506 if (GNUNET_OK != ret)
507 {
508 GNUNET_HELLO_builder_free (b);
509 return NULL;
510 }
511 }
512 return b;
250} 513}
251 514
252 515
253struct GNUNET_MQ_Envelope * 516struct GNUNET_MQ_Envelope *
254GNUNET_HELLO_builder_to_env (struct GNUNET_HELLO_Builder *builder) 517GNUNET_HELLO_builder_to_env (const struct GNUNET_HELLO_Builder *builder,
518 const struct GNUNET_CRYPTO_EddsaPrivateKey *priv)
255{ 519{
256 struct GNUNET_MQ_Envelope *env; 520 struct GNUNET_MQ_Envelope *env;
257 struct HelloUriMessage *msg; 521 struct HelloUriMessage *msg;
@@ -260,14 +524,15 @@ GNUNET_HELLO_builder_to_env (struct GNUNET_HELLO_Builder *builder)
260 blen = 0; 524 blen = 0;
261 GNUNET_assert (GNUNET_NO == 525 GNUNET_assert (GNUNET_NO ==
262 GNUNET_HELLO_builder_to_block (builder, 526 GNUNET_HELLO_builder_to_block (builder,
527 priv,
263 NULL, 528 NULL,
264 &blen)); 529 &blen));
265 env = GNUNET_MQ_msg_extra (msg, 530 env = GNUNET_MQ_msg_extra (msg,
266 blen, 531 blen,
267 GNUNET_MESSAGE_TYPE_HELLO_URI); 532 GNUNET_MESSAGE_TYPE_HELLO_URI);
268 msg->pid = builder->pid;
269 GNUNET_assert (GNUNET_OK == 533 GNUNET_assert (GNUNET_OK ==
270 GNUNET_HELLO_builder_to_block (builder, 534 GNUNET_HELLO_builder_to_block (builder,
535 priv,
271 &msg[1], 536 &msg[1],
272 &blen)); 537 &blen));
273 return env; 538 return env;
@@ -275,20 +540,80 @@ GNUNET_HELLO_builder_to_env (struct GNUNET_HELLO_Builder *builder)
275 540
276 541
277char * 542char *
278GNUNET_HELLO_builder_to_url (struct GNUNET_HELLO_Builder *builder) 543GNUNET_HELLO_builder_to_url (const struct GNUNET_HELLO_Builder *builder,
544 const struct GNUNET_CRYPTO_EddsaPrivateKey *priv)
279{ 545{
280 // FIXME! 546 struct GNUNET_CRYPTO_EddsaSignature sig;
281 return NULL; 547 struct GNUNET_TIME_Timestamp et;
548 char *result;
549 char *pids;
550 char *sigs;
551 const char *sep = "?";
552
553 et = GNUNET_TIME_relative_to_timestamp (HELLO_ADDRESS_EXPIRATION);
554 sign_hello (builder,
555 et,
556 priv,
557 &sig);
558 pids = GNUNET_STRINGS_data_to_string_alloc (&builder->pid,
559 sizeof (builder->pid));
560 sigs = GNUNET_STRINGS_data_to_string_alloc (&sig,
561 sizeof (sig));
562 GNUNET_asprintf (&result,
563 "gnunet://hello/%s/%s/%llu",
564 pids,
565 sigs,
566 (unsigned long long) GNUNET_TIME_timestamp_to_s (et));
567 GNUNET_free (sigs);
568 GNUNET_free (pids);
569 for (struct Address *a = builder->a_head;
570 NULL != a;
571 a = a->next)
572 {
573 char *ue;
574 char *tmp;
575 int pfx_len;
576 const char *eou;
577
578 eou = strstr (a->uri,
579 "://");
580 if (NULL == eou)
581 {
582 GNUNET_break (0);
583 GNUNET_free (result);
584 return NULL;
585 }
586 pfx_len = eou - a->uri;
587 eou += 3;
588 GNUNET_STRINGS_urlencode (eou,
589 a->uri_len - 4 - pfx_len,
590 &ue);
591 GNUNET_asprintf (&tmp,
592 "%s%s%.*s=%s",
593 result,
594 sep,
595 pfx_len,
596 a->uri,
597 ue);
598 GNUNET_free (ue);
599 GNUNET_free (result);
600 result = tmp;
601 sep = "&";
602 }
603 return result;
282} 604}
283 605
284 606
285enum GNUNET_GenericReturnValue 607enum GNUNET_GenericReturnValue
286GNUNET_HELLO_builder_to_block (struct GNUNET_HELLO_Builder *builder, 608GNUNET_HELLO_builder_to_block (const struct GNUNET_HELLO_Builder *builder,
609 const struct GNUNET_CRYPTO_EddsaPrivateKey *priv,
287 void *block, 610 void *block,
288 size_t *block_size) 611 size_t *block_size)
289{ 612{
290 size_t needed = sizeof (struct GNUNET_PeerIdentity); 613 struct BlockHeader bh;
614 size_t needed = sizeof (bh);
291 char *pos; 615 char *pos;
616 struct GNUNET_TIME_Timestamp et;
292 617
293 for (struct Address *a = builder->a_head; 618 for (struct Address *a = builder->a_head;
294 NULL != a; 619 NULL != a;
@@ -303,10 +628,17 @@ GNUNET_HELLO_builder_to_block (struct GNUNET_HELLO_Builder *builder,
303 *block_size = needed; 628 *block_size = needed;
304 return GNUNET_NO; 629 return GNUNET_NO;
305 } 630 }
631 bh.pid = builder->pid;
632 et = GNUNET_TIME_relative_to_timestamp (HELLO_ADDRESS_EXPIRATION);
633 bh.expiration_time = GNUNET_TIME_absolute_hton (et.abs_time);
634 sign_hello (builder,
635 et,
636 priv,
637 &bh.sig);
306 memcpy (block, 638 memcpy (block,
307 &builder->pid, 639 &bh,
308 sizeof (builder->pid)); 640 sizeof (bh));
309 pos = block + sizeof (builder->pid); 641 pos = block + sizeof (bh);
310 for (struct Address *a = builder->a_head; 642 for (struct Address *a = builder->a_head;
311 NULL != a; 643 NULL != a;
312 a = a->next) 644 a = a->next)
@@ -327,7 +659,26 @@ GNUNET_HELLO_builder_add_address (struct GNUNET_HELLO_Builder *builder,
327{ 659{
328 size_t alen = strlen (address) + 1; 660 size_t alen = strlen (address) + 1;
329 struct Address *a; 661 struct Address *a;
662 const char *e;
330 663
664 if (NULL == (e = strstr (address,
665 "://")))
666 {
667 GNUNET_break_op (0);
668 return GNUNET_SYSERR;
669 }
670 if (e == address)
671 {
672 GNUNET_break_op (0);
673 return GNUNET_SYSERR;
674 }
675 for (const char *p = address; p != e; p++)
676 if ( (! isalpha ((unsigned char) *p)) &&
677 ('+' != *p) )
678 {
679 GNUNET_break_op (0);
680 return GNUNET_SYSERR;
681 }
331 /* check for duplicates */ 682 /* check for duplicates */
332 for (a = builder->a_head; 683 for (a = builder->a_head;
333 NULL != a; 684 NULL != a;
@@ -341,9 +692,10 @@ GNUNET_HELLO_builder_add_address (struct GNUNET_HELLO_Builder *builder,
341 address, 692 address,
342 alen); 693 alen);
343 a->uri = (const char *) &a[1]; 694 a->uri = (const char *) &a[1];
344 GNUNET_CONTAINER_DLL_insert (builder->a_head, 695 GNUNET_CONTAINER_DLL_insert_tail (builder->a_head,
345 builder->a_tail, 696 builder->a_tail,
346 a); 697 a);
698 builder->a_length++;
347 return GNUNET_OK; 699 return GNUNET_OK;
348} 700}
349 701
@@ -366,6 +718,7 @@ GNUNET_HELLO_builder_del_address (struct GNUNET_HELLO_Builder *builder,
366 GNUNET_CONTAINER_DLL_remove (builder->a_head, 718 GNUNET_CONTAINER_DLL_remove (builder->a_head,
367 builder->a_tail, 719 builder->a_tail,
368 a); 720 a);
721 builder->a_length--;
369 GNUNET_free (a); 722 GNUNET_free (a);
370 return GNUNET_OK; 723 return GNUNET_OK;
371} 724}