aboutsummaryrefslogtreecommitdiff
path: root/src/service/revocation
diff options
context:
space:
mode:
Diffstat (limited to 'src/service/revocation')
-rw-r--r--src/service/revocation/.gitignore5
-rw-r--r--src/service/revocation/Makefile.am74
-rw-r--r--src/service/revocation/gnunet-service-revocation.c1066
-rw-r--r--src/service/revocation/meson.build44
-rw-r--r--src/service/revocation/revocation.conf.in19
-rw-r--r--src/service/revocation/revocation.h115
-rw-r--r--src/service/revocation/revocation_api.c334
-rw-r--r--src/service/revocation/test_revocation.c419
-rw-r--r--src/service/revocation/test_revocation.conf31
-rw-r--r--src/service/revocation/test_revocation_testvectors.c297
10 files changed, 2404 insertions, 0 deletions
diff --git a/src/service/revocation/.gitignore b/src/service/revocation/.gitignore
new file mode 100644
index 000000000..1432f7922
--- /dev/null
+++ b/src/service/revocation/.gitignore
@@ -0,0 +1,5 @@
1gnunet-service-revocation
2gnunet-revocation
3test_revocation
4test_local_revocation.py
5gnunet-revocation-tvg
diff --git a/src/service/revocation/Makefile.am b/src/service/revocation/Makefile.am
new file mode 100644
index 000000000..18bf21fb0
--- /dev/null
+++ b/src/service/revocation/Makefile.am
@@ -0,0 +1,74 @@
1# This Makefile.am is in the public domain
2AM_CPPFLAGS = -I$(top_srcdir)/src/include
3
4plugindir = $(libdir)/gnunet
5
6if USE_COVERAGE
7 AM_CFLAGS = --coverage -O0
8 XLIB = -lgcov
9endif
10
11pkgcfgdir= $(pkgdatadir)/config.d/
12
13libexecdir= $(pkglibdir)/libexec/
14
15pkgcfg_DATA = \
16 revocation.conf
17
18test_revocation_lsd0001testvectors_SOURCES = \
19 test_revocation_testvectors.c
20test_revocation_lsd0001testvectors_LDADD = \
21 $(top_builddir)/src/service/testing/libgnunettesting.la \
22 $(top_builddir)/src/service/identity/libgnunetidentity.la \
23 libgnunetrevocation.la \
24 $(top_builddir)/src/lib/util/libgnunetutil.la
25
26lib_LTLIBRARIES = libgnunetrevocation.la
27
28libgnunetrevocation_la_SOURCES = \
29 revocation_api.c revocation.h
30libgnunetrevocation_la_LIBADD = \
31 $(top_builddir)/src/lib/util/libgnunetutil.la \
32 $(top_builddir)/src/lib/gnsrecord/libgnunetgnsrecord.la \
33 $(LIBGCRYPT_LIBS) \
34 $(GN_LIBINTL) $(XLIB) -lgcrypt
35libgnunetrevocation_la_LDFLAGS = \
36 $(GN_LIB_LDFLAGS) \
37 -version-info 0:0:0
38
39libexec_PROGRAMS = \
40 gnunet-service-revocation
41
42gnunet_service_revocation_SOURCES = \
43 gnunet-service-revocation.c
44gnunet_service_revocation_LDADD = \
45 libgnunetrevocation.la \
46 $(top_builddir)/src/service/core/libgnunetcore.la \
47 $(top_builddir)/src/service/setu/libgnunetsetu.la \
48 $(top_builddir)/src/service/statistics/libgnunetstatistics.la \
49 $(top_builddir)/src/lib/gnsrecord/libgnunetgnsrecord.la \
50 $(top_builddir)/src/lib/util/libgnunetutil.la \
51 -lm \
52 $(GN_LIBINTL)
53
54test_revocation_SOURCES = \
55 test_revocation.c
56test_revocation_LDADD = \
57 $(top_builddir)/src/service/identity/libgnunetidentity.la \
58 libgnunetrevocation.la \
59 $(top_builddir)/src//core/libgnunetcore.la \
60 $(top_builddir)/src/lib/util/libgnunetutil.la \
61 $(top_builddir)/src/testbed/libgnunettestbed.la
62
63check_PROGRAMS = \
64 #test_revocation \
65 #test_revocation_lsd0001testvectors
66
67if ENABLE_TEST_RUN
68 AM_TESTS_ENVIRONMENT=export GNUNET_PREFIX=$${GNUNET_PREFIX:-@libdir@};export PATH=$${GNUNET_PREFIX:-@prefix@}/bin:$$PATH;unset XDG_DATA_HOME;unset XDG_CONFIG_HOME;
69 TESTS = \
70 $(check_SCRIPTS) \
71 $(check_PROGRAMS)
72endif
73
74EXTRA_DIST = test_revocation.conf
diff --git a/src/service/revocation/gnunet-service-revocation.c b/src/service/revocation/gnunet-service-revocation.c
new file mode 100644
index 000000000..8a8610758
--- /dev/null
+++ b/src/service/revocation/gnunet-service-revocation.c
@@ -0,0 +1,1066 @@
1/*
2 This file is part of GNUnet.
3 Copyright (C) 2013, 2014, 2016 GNUnet e.V.
4
5 GNUnet is free software: you can redistribute it and/or modify it
6 under the terms of the GNU Affero General Public License as published
7 by the Free Software Foundation, either version 3 of the License,
8 or (at your 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 Affero General Public License for more details.
14
15 You should have received a copy of the GNU Affero General Public License
16 along with this program. If not, see <http://www.gnu.org/licenses/>.
17
18 SPDX-License-Identifier: AGPL3.0-or-later
19 */
20
21/**
22 * @file revocation/gnunet-service-revocation.c
23 * @brief key revocation service
24 * @author Christian Grothoff
25 *
26 * The purpose of this service is to allow users to permanently revoke
27 * (compromised) keys. This is done by flooding the network with the
28 * revocation requests. To reduce the attack potential offered by such
29 * flooding, revocations must include a proof of work. We use the
30 * set service for efficiently computing the union of revocations of
31 * peers that connect.
32 *
33 * TODO:
34 * - optimization: avoid sending revocation back to peer that we got it from;
35 * - optimization: have randomized delay in sending revocations to other peers
36 * to make it rare to traverse each link twice (NSE-style)
37 */
38#include "platform.h"
39#include <math.h>
40#include "gnunet_util_lib.h"
41#include "gnunet_gnsrecord_lib.h"
42#include "gnunet_block_lib.h"
43#include "gnunet_constants.h"
44#include "gnunet_protocols.h"
45#include "gnunet_signatures.h"
46#include "gnunet_statistics_service.h"
47#include "gnunet_core_service.h"
48#include "gnunet_revocation_service.h"
49#include "gnunet_setu_service.h"
50#include "revocation.h"
51#include <gcrypt.h>
52
53
54/**
55 * Per-peer information.
56 */
57struct PeerEntry
58{
59 /**
60 * Queue for sending messages to this peer.
61 */
62 struct GNUNET_MQ_Handle *mq;
63
64 /**
65 * What is the identity of the peer?
66 */
67 struct GNUNET_PeerIdentity id;
68
69 /**
70 * Tasked used to trigger the set union operation.
71 */
72 struct GNUNET_SCHEDULER_Task *transmit_task;
73
74 /**
75 * Handle to active set union operation (over revocation sets).
76 */
77 struct GNUNET_SETU_OperationHandle *so;
78};
79
80
81/**
82 * Set from all revocations known to us.
83 */
84static struct GNUNET_SETU_Handle *revocation_set;
85
86/**
87 * Hash map with all revoked keys, maps the hash of the public key
88 * to the respective `struct RevokeMessage`.
89 */
90static struct GNUNET_CONTAINER_MultiHashMap *revocation_map;
91
92/**
93 * Handle to our current configuration.
94 */
95static const struct GNUNET_CONFIGURATION_Handle *cfg;
96
97/**
98 * Handle to the statistics service.
99 */
100static struct GNUNET_STATISTICS_Handle *stats;
101
102/**
103 * Handle to the core service (for flooding)
104 */
105static struct GNUNET_CORE_Handle *core_api;
106
107/**
108 * Map of all connected peers.
109 */
110static struct GNUNET_CONTAINER_MultiPeerMap *peers;
111
112/**
113 * The peer identity of this peer.
114 */
115static struct GNUNET_PeerIdentity my_identity;
116
117/**
118 * File handle for the revocation database.
119 */
120static struct GNUNET_DISK_FileHandle *revocation_db;
121
122/**
123 * Handle for us listening to incoming revocation set union requests.
124 */
125static struct GNUNET_SETU_ListenHandle *revocation_union_listen_handle;
126
127/**
128 * Amount of work required (W-bit collisions) for REVOCATION proofs, in collision-bits.
129 */
130static unsigned long long revocation_work_required;
131
132/**
133 * Length of an expiration expoch
134 */
135static struct GNUNET_TIME_Relative epoch_duration;
136
137/**
138 * Our application ID for set union operations. Must be the
139 * same for all (compatible) peers.
140 */
141static struct GNUNET_HashCode revocation_set_union_app_id;
142
143
144/**
145 * Create a new PeerEntry and add it to the peers multipeermap.
146 *
147 * @param peer the peer identity
148 * @return a pointer to the new PeerEntry
149 */
150static struct PeerEntry *
151new_peer_entry (const struct GNUNET_PeerIdentity *peer)
152{
153 struct PeerEntry *peer_entry;
154
155 peer_entry = GNUNET_new (struct PeerEntry);
156 peer_entry->id = *peer;
157 GNUNET_assert (GNUNET_OK ==
158 GNUNET_CONTAINER_multipeermap_put (peers,
159 &peer_entry->id,
160 peer_entry,
161 GNUNET_CONTAINER_MULTIHASHMAPOPTION_UNIQUE_ONLY));
162 return peer_entry;
163}
164
165
166/**
167 * An revoke message has been received, check that it is well-formed.
168 *
169 * @param rm the message to verify
170 * @return #GNUNET_YES if the message is verified
171 * #GNUNET_NO if the key/signature don't verify
172 */
173static enum GNUNET_GenericReturnValue
174verify_revoke_message (const struct RevokeMessage *rm)
175{
176 const struct GNUNET_GNSRECORD_PowP *pow
177 = (const struct GNUNET_GNSRECORD_PowP *) &rm[1];
178
179 if (GNUNET_YES !=
180 GNUNET_GNSRECORD_check_pow (pow,
181 (unsigned int) revocation_work_required,
182 epoch_duration))
183 {
184 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
185 "Proof of work invalid!\n");
186 GNUNET_break_op (0);
187 return GNUNET_NO;
188 }
189 return GNUNET_YES;
190}
191
192
193/**
194 * Handle client connecting to the service.
195 *
196 * @param cls NULL
197 * @param client the new client
198 * @param mq the message queue of @a client
199 * @return @a client
200 */
201static void *
202client_connect_cb (void *cls,
203 struct GNUNET_SERVICE_Client *client,
204 struct GNUNET_MQ_Handle *mq)
205{
206 return client;
207}
208
209
210/**
211 * Handle client connecting to the service.
212 *
213 * @param cls NULL
214 * @param client the new client
215 * @param app_cls must alias @a client
216 */
217static void
218client_disconnect_cb (void *cls,
219 struct GNUNET_SERVICE_Client *client,
220 void *app_cls)
221{
222 GNUNET_assert (client == app_cls);
223}
224
225
226static int
227check_query_message (void *cls,
228 const struct QueryMessage *qm)
229{
230 uint16_t size;
231
232 size = ntohs (qm->header.size);
233 if (size <= sizeof(struct RevokeMessage) ||
234 (size > UINT16_MAX))
235 {
236 GNUNET_break (0);
237 return GNUNET_SYSERR;
238 }
239 return GNUNET_OK;
240
241}
242
243
244/**
245 * Handle QUERY message from client.
246 *
247 * @param cls client who sent the message
248 * @param qm the message received
249 */
250static void
251handle_query_message (void *cls,
252 const struct QueryMessage *qm)
253{
254 struct GNUNET_SERVICE_Client *client = cls;
255 struct GNUNET_CRYPTO_PublicKey zone;
256 struct GNUNET_MQ_Envelope *env;
257 struct QueryResponseMessage *qrm;
258 struct GNUNET_HashCode hc;
259 int res;
260 size_t key_len;
261 size_t read;
262
263 key_len = ntohl (qm->key_len);
264 if ((GNUNET_SYSERR ==
265 GNUNET_CRYPTO_read_public_key_from_buffer (&qm[1], key_len,
266 &zone, &read)) ||
267 (read != key_len))
268 {
269 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
270 "Unable to parse query public key\n");
271 GNUNET_SERVICE_client_drop (client);
272 return;
273 }
274 GNUNET_CRYPTO_hash (&qm[1],
275 key_len,
276 &hc);
277 res = GNUNET_CONTAINER_multihashmap_contains (revocation_map,
278 &hc);
279 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
280 (GNUNET_NO == res)
281 ? "Received revocation check for valid key `%s' from client\n"
282 : "Received revocation check for revoked key `%s' from client\n",
283 GNUNET_h2s (&hc));
284 env = GNUNET_MQ_msg (qrm,
285 GNUNET_MESSAGE_TYPE_REVOCATION_QUERY_RESPONSE);
286 qrm->is_valid = htonl ((GNUNET_YES == res) ? GNUNET_NO : GNUNET_YES);
287 GNUNET_MQ_send (GNUNET_SERVICE_client_get_mq (client),
288 env);
289 GNUNET_SERVICE_client_continue (client);
290}
291
292
293/**
294 * Flood the given revocation message to all neighbours.
295 *
296 * @param cls the `struct RevokeMessage` to flood
297 * @param target a neighbour
298 * @param value our `struct PeerEntry` for the neighbour
299 * @return #GNUNET_OK (continue to iterate)
300 */
301static enum GNUNET_GenericReturnValue
302do_flood (void *cls,
303 const struct GNUNET_PeerIdentity *target,
304 void *value)
305{
306 const struct RevokeMessage *rm = cls;
307 struct PeerEntry *pe = value;
308 struct GNUNET_MQ_Envelope *e;
309 struct RevokeMessage *cp;
310
311 if (NULL == pe->mq)
312 return GNUNET_OK; /* peer connected to us via SET,
313 but we have no direct CORE
314 connection for flooding */
315 e = GNUNET_MQ_msg_extra (cp,
316 htonl (rm->pow_size),
317 GNUNET_MESSAGE_TYPE_REVOCATION_REVOKE);
318 *cp = *rm;
319 memcpy (&cp[1],
320 &rm[1],
321 htonl (rm->pow_size));
322 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
323 "Flooding revocation to `%s'\n",
324 GNUNET_i2s (target));
325 GNUNET_MQ_send (pe->mq,
326 e);
327 return GNUNET_OK;
328}
329
330
331/**
332 * Publicize revocation message. Stores the message locally in the
333 * database and passes it to all connected neighbours (and adds it to
334 * the set for future connections).
335 *
336 * @param rm message to publicize
337 * @return #GNUNET_OK on success, #GNUNET_NO if we encountered an error,
338 * #GNUNET_SYSERR if the message was malformed
339 */
340static enum GNUNET_GenericReturnValue
341publicize_rm (const struct RevokeMessage *rm)
342{
343 struct RevokeMessage *cp;
344 struct GNUNET_HashCode hc;
345 struct GNUNET_SETU_Element e;
346 ssize_t pklen;
347 const struct GNUNET_GNSRECORD_PowP *pow
348 = (const struct GNUNET_GNSRECORD_PowP *) &rm[1];
349 const struct GNUNET_CRYPTO_PublicKey *pk
350 = (const struct GNUNET_CRYPTO_PublicKey *) &pow[1];
351
352 /** FIXME yeah this works, but should we have a key length somewhere? */
353 pklen = GNUNET_CRYPTO_public_key_get_length (pk);
354 if (0 > pklen)
355 {
356 GNUNET_break_op (0);
357 return GNUNET_SYSERR;
358 }
359 GNUNET_CRYPTO_hash (pk,
360 pklen,
361 &hc);
362 if (GNUNET_YES ==
363 GNUNET_CONTAINER_multihashmap_contains (revocation_map,
364 &hc))
365 {
366 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
367 "Duplicate revocation received from peer. Ignored.\n");
368 return GNUNET_OK;
369 }
370 if (GNUNET_OK !=
371 verify_revoke_message (rm))
372 {
373 GNUNET_break_op (0);
374 return GNUNET_SYSERR;
375 }
376 /* write to disk */
377 if (sizeof(struct RevokeMessage) !=
378 GNUNET_DISK_file_write (revocation_db,
379 rm,
380 sizeof(struct RevokeMessage)))
381 {
382 GNUNET_log_strerror (GNUNET_ERROR_TYPE_ERROR,
383 "write");
384 return GNUNET_NO;
385 }
386 if (GNUNET_OK !=
387 GNUNET_DISK_file_sync (revocation_db))
388 {
389 GNUNET_log_strerror (GNUNET_ERROR_TYPE_ERROR,
390 "sync");
391 return GNUNET_NO;
392 }
393 /* keep copy in memory */
394 cp = (struct RevokeMessage *) GNUNET_copy_message (&rm->header);
395 GNUNET_break (GNUNET_OK ==
396 GNUNET_CONTAINER_multihashmap_put (revocation_map,
397 &hc,
398 cp,
399 GNUNET_CONTAINER_MULTIHASHMAPOPTION_UNIQUE_ONLY));
400 /* add to set for future connections */
401 e.size = htons (rm->header.size);
402 e.element_type = GNUNET_BLOCK_TYPE_REVOCATION;
403 e.data = rm;
404 if (GNUNET_OK !=
405 GNUNET_SETU_add_element (revocation_set,
406 &e,
407 NULL,
408 NULL))
409 {
410 GNUNET_break (0);
411 return GNUNET_OK;
412 }
413 else
414 {
415 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
416 "Added revocation info to SET\n");
417 }
418 /* flood to neighbours */
419 GNUNET_CONTAINER_multipeermap_iterate (peers,
420 &do_flood,
421 cp);
422 return GNUNET_OK;
423}
424
425
426static int
427check_revoke_message (void *cls,
428 const struct RevokeMessage *rm)
429{
430 uint16_t size;
431
432 size = ntohs (rm->header.size);
433 if (size <= sizeof(struct RevokeMessage) ||
434 (size > UINT16_MAX))
435 {
436 GNUNET_break (0);
437 return GNUNET_SYSERR;
438 }
439 return GNUNET_OK;
440
441}
442
443
444/**
445 * Handle REVOKE message from client.
446 *
447 * @param cls client who sent the message
448 * @param rm the message received
449 */
450static void
451handle_revoke_message (void *cls,
452 const struct RevokeMessage *rm)
453{
454 struct GNUNET_SERVICE_Client *client = cls;
455 struct GNUNET_MQ_Envelope *env;
456 struct RevocationResponseMessage *rrm;
457 int ret;
458
459 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
460 "Received REVOKE message from client\n");
461 if (GNUNET_SYSERR == (ret = publicize_rm (rm)))
462 {
463 GNUNET_break_op (0);
464 GNUNET_SERVICE_client_drop (client);
465 return;
466 }
467 env = GNUNET_MQ_msg (rrm,
468 GNUNET_MESSAGE_TYPE_REVOCATION_REVOKE_RESPONSE);
469 rrm->is_valid = htonl ((GNUNET_OK == ret) ? GNUNET_NO : GNUNET_YES);
470 GNUNET_MQ_send (GNUNET_SERVICE_client_get_mq (client),
471 env);
472 GNUNET_SERVICE_client_continue (client);
473}
474
475
476static int
477check_p2p_revoke (void *cls,
478 const struct RevokeMessage *rm)
479{
480 uint16_t size;
481
482 size = ntohs (rm->header.size);
483 if (size <= sizeof(struct RevokeMessage))
484 {
485 GNUNET_break (0);
486 return GNUNET_SYSERR;
487 }
488 return GNUNET_OK;
489
490}
491
492
493/**
494 * Core handler for flooded revocation messages.
495 *
496 * @param cls closure unused
497 * @param rm revocation message
498 */
499static void
500handle_p2p_revoke (void *cls,
501 const struct RevokeMessage *rm)
502{
503 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
504 "Received REVOKE message\n");
505 GNUNET_break_op (GNUNET_SYSERR !=
506 publicize_rm (rm));
507}
508
509
510/**
511 * Callback for set operation results. Called for each element in the
512 * result set. Each element contains a revocation, which we should
513 * validate and then add to our revocation list (and set).
514 *
515 * @param cls closure
516 * @param element a result element, only valid if status is #GNUNET_SETU_STATUS_OK
517 * @param current_size current set size
518 * @param status see `enum GNUNET_SETU_Status`
519 */
520static void
521add_revocation (void *cls,
522 const struct GNUNET_SETU_Element *element,
523 uint64_t current_size,
524 enum GNUNET_SETU_Status status)
525{
526 struct PeerEntry *peer_entry = cls;
527 const struct RevokeMessage *rm;
528
529 switch (status)
530 {
531 case GNUNET_SETU_STATUS_ADD_LOCAL:
532 if (element->size != sizeof(struct RevokeMessage))
533 {
534 GNUNET_break_op (0);
535 return;
536 }
537 if (GNUNET_BLOCK_TYPE_REVOCATION != element->element_type)
538 {
539 GNUNET_STATISTICS_update (stats,
540 gettext_noop (
541 "# unsupported revocations received via set union"),
542 1,
543 GNUNET_NO);
544 return;
545 }
546 rm = element->data;
547 (void) handle_p2p_revoke (NULL,
548 rm);
549 GNUNET_STATISTICS_update (stats,
550 gettext_noop (
551 "# revocation messages received via set union"),
552 1, GNUNET_NO);
553 break;
554 case GNUNET_SETU_STATUS_FAILURE:
555 GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
556 _ ("Error computing revocation set union with %s\n"),
557 GNUNET_i2s (&peer_entry->id));
558 peer_entry->so = NULL;
559 GNUNET_STATISTICS_update (stats,
560 gettext_noop ("# revocation set unions failed"),
561 1,
562 GNUNET_NO);
563 break;
564 case GNUNET_SETU_STATUS_DONE:
565 peer_entry->so = NULL;
566 GNUNET_STATISTICS_update (stats,
567 gettext_noop (
568 "# revocation set unions completed"),
569 1,
570 GNUNET_NO);
571 break;
572 default:
573 GNUNET_break (0);
574 break;
575 }
576}
577
578
579/**
580 * The timeout for performing the set union has expired,
581 * run the set operation on the revocation certificates.
582 *
583 * @param cls NULL
584 */
585static void
586transmit_task_cb (void *cls)
587{
588 struct PeerEntry *peer_entry = cls;
589
590 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
591 "Starting set exchange with peer `%s'\n",
592 GNUNET_i2s (&peer_entry->id));
593 peer_entry->transmit_task = NULL;
594 GNUNET_assert (NULL == peer_entry->so);
595 peer_entry->so = GNUNET_SETU_prepare (&peer_entry->id,
596 &revocation_set_union_app_id,
597 NULL,
598 (struct GNUNET_SETU_Option[]) { { 0 } },
599 &add_revocation,
600 peer_entry);
601 if (GNUNET_OK !=
602 GNUNET_SETU_commit (peer_entry->so,
603 revocation_set))
604 {
605 GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
606 _ ("SET service crashed, terminating revocation service\n"));
607 GNUNET_SCHEDULER_shutdown ();
608 return;
609 }
610}
611
612
613/**
614 * Method called whenever a peer connects. Sets up the PeerEntry and
615 * schedules the initial revocation set exchange with this peer.
616 *
617 * @param cls closure
618 * @param peer peer identity this notification is about
619 */
620static void *
621handle_core_connect (void *cls,
622 const struct GNUNET_PeerIdentity *peer,
623 struct GNUNET_MQ_Handle *mq)
624{
625 struct PeerEntry *peer_entry;
626 struct GNUNET_HashCode my_hash;
627 struct GNUNET_HashCode peer_hash;
628
629 if (0 == GNUNET_memcmp (peer,
630 &my_identity))
631 {
632 return NULL;
633 }
634
635 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
636 "Peer `%s' connected to us\n",
637 GNUNET_i2s (peer));
638 GNUNET_STATISTICS_update (stats,
639 "# peers connected",
640 1,
641 GNUNET_NO);
642 peer_entry = GNUNET_CONTAINER_multipeermap_get (peers,
643 peer);
644 if (NULL != peer_entry)
645 {
646 /* This can happen if "core"'s notification is a tad late
647 and CADET+SET were faster and already produced a
648 #handle_revocation_union_request() for us to deal
649 with. This should be rare, but isn't impossible. */
650 peer_entry->mq = mq;
651 return peer_entry;
652 }
653 peer_entry = new_peer_entry (peer);
654 peer_entry->mq = mq;
655 GNUNET_CRYPTO_hash (&my_identity,
656 sizeof(my_identity),
657 &my_hash);
658 GNUNET_CRYPTO_hash (peer,
659 sizeof(*peer),
660 &peer_hash);
661 if (0 < GNUNET_CRYPTO_hash_cmp (&my_hash,
662 &peer_hash))
663 {
664 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
665 "Starting SET operation with peer `%s'\n",
666 GNUNET_i2s (peer));
667 peer_entry->transmit_task =
668 GNUNET_SCHEDULER_add_delayed (GNUNET_TIME_UNIT_SECONDS,
669 &transmit_task_cb,
670 peer_entry);
671 }
672 return peer_entry;
673}
674
675
676/**
677 * Method called whenever a peer disconnects. Deletes the PeerEntry and cancels
678 * any pending transmission requests to that peer.
679 *
680 * @param cls closure
681 * @param peer peer identity this notification is about
682 * @param internal_cls our `struct PeerEntry` for this peer
683 */
684static void
685handle_core_disconnect (void *cls,
686 const struct GNUNET_PeerIdentity *peer,
687 void *internal_cls)
688{
689 struct PeerEntry *peer_entry = internal_cls;
690
691 if (0 == GNUNET_memcmp (peer,
692 &my_identity))
693 return;
694 GNUNET_assert (NULL != peer_entry);
695 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
696 "Peer `%s' disconnected from us\n",
697 GNUNET_i2s (peer));
698 GNUNET_assert (GNUNET_YES ==
699 GNUNET_CONTAINER_multipeermap_remove (peers,
700 peer,
701 peer_entry));
702 if (NULL != peer_entry->transmit_task)
703 {
704 GNUNET_SCHEDULER_cancel (peer_entry->transmit_task);
705 peer_entry->transmit_task = NULL;
706 }
707 if (NULL != peer_entry->so)
708 {
709 GNUNET_SETU_operation_cancel (peer_entry->so);
710 peer_entry->so = NULL;
711 }
712 GNUNET_free (peer_entry);
713 GNUNET_STATISTICS_update (stats,
714 "# peers connected",
715 -1,
716 GNUNET_NO);
717}
718
719
720/**
721 * Free all values in a hash map.
722 *
723 * @param cls NULL
724 * @param key the key
725 * @param value value to free
726 * @return #GNUNET_OK (continue to iterate)
727 */
728static int
729free_entry (void *cls,
730 const struct GNUNET_HashCode *key,
731 void *value)
732{
733 GNUNET_free (value);
734 return GNUNET_OK;
735}
736
737
738/**
739 * Task run during shutdown.
740 *
741 * @param cls unused
742 */
743static void
744shutdown_task (void *cls)
745{
746 if (NULL != revocation_set)
747 {
748 GNUNET_SETU_destroy (revocation_set);
749 revocation_set = NULL;
750 }
751 if (NULL != revocation_union_listen_handle)
752 {
753 GNUNET_SETU_listen_cancel (revocation_union_listen_handle);
754 revocation_union_listen_handle = NULL;
755 }
756 if (NULL != core_api)
757 {
758 GNUNET_CORE_disconnect (core_api);
759 core_api = NULL;
760 }
761 if (NULL != stats)
762 {
763 GNUNET_STATISTICS_destroy (stats, GNUNET_NO);
764 stats = NULL;
765 }
766 if (NULL != peers)
767 {
768 GNUNET_CONTAINER_multipeermap_destroy (peers);
769 peers = NULL;
770 }
771 if (NULL != revocation_db)
772 {
773 GNUNET_DISK_file_close (revocation_db);
774 revocation_db = NULL;
775 }
776 GNUNET_CONTAINER_multihashmap_iterate (revocation_map,
777 &free_entry,
778 NULL);
779 GNUNET_CONTAINER_multihashmap_destroy (revocation_map);
780}
781
782
783/**
784 * Called on core init/fail.
785 *
786 * @param cls service closure
787 * @param identity the public identity of this peer
788 */
789static void
790core_init (void *cls,
791 const struct GNUNET_PeerIdentity *identity)
792{
793 if (NULL == identity)
794 {
795 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
796 "Connection to core FAILED!\n");
797 GNUNET_SCHEDULER_shutdown ();
798 return;
799 }
800 my_identity = *identity;
801}
802
803
804/**
805 * Called when another peer wants to do a set operation with the
806 * local peer. If a listen error occurs, the 'request' is NULL.
807 *
808 * @param cls closure
809 * @param other_peer the other peer
810 * @param context_msg message with application specific information from
811 * the other peer
812 * @param request request from the other peer (never NULL), use GNUNET_SETU_accept()
813 * to accept it, otherwise the request will be refused
814 * Note that we can't just return value from the listen callback,
815 * as it is also necessary to specify the set we want to do the
816 * operation with, which sometimes can be derived from the context
817 * message. It's necessary to specify the timeout.
818 */
819static void
820handle_revocation_union_request (void *cls,
821 const struct GNUNET_PeerIdentity *other_peer,
822 const struct GNUNET_MessageHeader *context_msg,
823 struct GNUNET_SETU_Request *request)
824{
825 struct PeerEntry *peer_entry;
826
827 if (NULL == request)
828 {
829 GNUNET_break (0);
830 return;
831 }
832 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
833 "Received set exchange request from peer `%s'\n",
834 GNUNET_i2s (other_peer));
835 peer_entry = GNUNET_CONTAINER_multipeermap_get (peers,
836 other_peer);
837 if (NULL == peer_entry)
838 {
839 peer_entry = new_peer_entry (other_peer);
840 }
841 if (NULL != peer_entry->so)
842 {
843 GNUNET_break_op (0);
844 return;
845 }
846 peer_entry->so = GNUNET_SETU_accept (request,
847 (struct GNUNET_SETU_Option[]) { { 0 } },
848 &add_revocation,
849 peer_entry);
850 if (GNUNET_OK !=
851 GNUNET_SETU_commit (peer_entry->so,
852 revocation_set))
853 {
854 GNUNET_break (0);
855 GNUNET_SCHEDULER_shutdown ();
856 return;
857 }
858}
859
860
861/**
862 * Handle network size estimate clients.
863 *
864 * @param cls closure
865 * @param server the initialized server
866 * @param c configuration to use
867 */
868static void
869run (void *cls,
870 const struct GNUNET_CONFIGURATION_Handle *c,
871 struct GNUNET_SERVICE_Handle *service)
872{
873 struct GNUNET_MQ_MessageHandler core_handlers[] = {
874 GNUNET_MQ_hd_var_size (p2p_revoke,
875 GNUNET_MESSAGE_TYPE_REVOCATION_REVOKE,
876 struct RevokeMessage,
877 NULL),
878 GNUNET_MQ_handler_end ()
879 };
880 char *fn;
881 uint64_t left;
882 struct RevokeMessage *rm;
883 struct GNUNET_HashCode hc;
884 const struct GNUNET_CRYPTO_PublicKey *pk;
885
886 GNUNET_CRYPTO_hash ("revocation-set-union-application-id",
887 strlen ("revocation-set-union-application-id"),
888 &revocation_set_union_app_id);
889 if (GNUNET_OK !=
890 GNUNET_CONFIGURATION_get_value_filename (c,
891 "REVOCATION",
892 "DATABASE",
893 &fn))
894 {
895 GNUNET_log_config_missing (GNUNET_ERROR_TYPE_ERROR,
896 "REVOCATION",
897 "DATABASE");
898 GNUNET_SCHEDULER_shutdown ();
899 return;
900 }
901 cfg = c;
902 revocation_map = GNUNET_CONTAINER_multihashmap_create (16,
903 GNUNET_NO);
904 GNUNET_SCHEDULER_add_shutdown (&shutdown_task,
905 NULL);
906 if (GNUNET_OK !=
907 GNUNET_CONFIGURATION_get_value_number (cfg,
908 "REVOCATION",
909 "WORKBITS",
910 &revocation_work_required))
911 {
912 GNUNET_log_config_missing (GNUNET_ERROR_TYPE_ERROR,
913 "REVOCATION",
914 "WORKBITS");
915 GNUNET_SCHEDULER_shutdown ();
916 GNUNET_free (fn);
917 return;
918 }
919 if (revocation_work_required >= sizeof(struct GNUNET_HashCode) * 8)
920 {
921 GNUNET_log_config_invalid (GNUNET_ERROR_TYPE_ERROR,
922 "REVOCATION",
923 "WORKBITS",
924 _ ("Value is too large.\n"));
925 GNUNET_SCHEDULER_shutdown ();
926 GNUNET_free (fn);
927 return;
928 }
929 if (GNUNET_OK !=
930 GNUNET_CONFIGURATION_get_value_time (cfg,
931 "REVOCATION",
932 "EPOCH_DURATION",
933 &epoch_duration))
934 {
935 GNUNET_log_config_missing (GNUNET_ERROR_TYPE_ERROR,
936 "REVOCATION",
937 "EPOCH_DURATION");
938 GNUNET_SCHEDULER_shutdown ();
939 GNUNET_free (fn);
940 return;
941 }
942
943 revocation_set = GNUNET_SETU_create (cfg);
944 revocation_union_listen_handle
945 = GNUNET_SETU_listen (cfg,
946 &revocation_set_union_app_id,
947 &handle_revocation_union_request,
948 NULL);
949 revocation_db = GNUNET_DISK_file_open (fn,
950 GNUNET_DISK_OPEN_READWRITE
951 | GNUNET_DISK_OPEN_CREATE,
952 GNUNET_DISK_PERM_USER_READ
953 | GNUNET_DISK_PERM_USER_WRITE
954 | GNUNET_DISK_PERM_GROUP_READ
955 | GNUNET_DISK_PERM_OTHER_READ);
956 if (NULL == revocation_db)
957 {
958 GNUNET_log_config_invalid (GNUNET_ERROR_TYPE_ERROR,
959 "REVOCATION",
960 "DATABASE",
961 _ ("Could not open revocation database file!"));
962 GNUNET_SCHEDULER_shutdown ();
963 GNUNET_free (fn);
964 return;
965 }
966 if (GNUNET_OK !=
967 GNUNET_DISK_file_size (fn, &left, GNUNET_YES, GNUNET_YES))
968 left = 0;
969 while (left > sizeof(struct RevokeMessage))
970 {
971 rm = GNUNET_new (struct RevokeMessage);
972 if (sizeof(struct RevokeMessage) !=
973 GNUNET_DISK_file_read (revocation_db,
974 rm,
975 sizeof(struct RevokeMessage)))
976 {
977 GNUNET_log_strerror_file (GNUNET_ERROR_TYPE_ERROR,
978 "read",
979 fn);
980 GNUNET_free (rm);
981 GNUNET_SCHEDULER_shutdown ();
982 GNUNET_free (fn);
983 return;
984 }
985 struct GNUNET_GNSRECORD_PowP *pow = (struct
986 GNUNET_GNSRECORD_PowP *) &rm[1];
987 ssize_t ksize;
988 pk = (const struct GNUNET_CRYPTO_PublicKey *) &pow[1];
989 ksize = GNUNET_CRYPTO_public_key_get_length (pk);
990 if (0 > ksize)
991 {
992 GNUNET_break_op (0);
993 GNUNET_free (rm);
994 GNUNET_free (fn);
995 return;
996 }
997 GNUNET_CRYPTO_hash (pk,
998 ksize,
999 &hc);
1000 GNUNET_break (GNUNET_OK ==
1001 GNUNET_CONTAINER_multihashmap_put (revocation_map,
1002 &hc,
1003 rm,
1004 GNUNET_CONTAINER_MULTIHASHMAPOPTION_UNIQUE_ONLY));
1005 }
1006 GNUNET_free (fn);
1007
1008 peers = GNUNET_CONTAINER_multipeermap_create (128,
1009 GNUNET_YES);
1010 /* Connect to core service and register core handlers */
1011 core_api = GNUNET_CORE_connect (cfg, /* Main configuration */
1012 NULL, /* Closure passed to functions */
1013 &core_init, /* Call core_init once connected */
1014 &handle_core_connect, /* Handle connects */
1015 &handle_core_disconnect, /* Handle disconnects */
1016 core_handlers); /* Register these handlers */
1017 if (NULL == core_api)
1018 {
1019 GNUNET_SCHEDULER_shutdown ();
1020 return;
1021 }
1022 stats = GNUNET_STATISTICS_create ("revocation",
1023 cfg);
1024}
1025
1026
1027/**
1028 * Define "main" method using service macro.
1029 */
1030GNUNET_SERVICE_MAIN
1031 ("revocation",
1032 GNUNET_SERVICE_OPTION_NONE,
1033 &run,
1034 &client_connect_cb,
1035 &client_disconnect_cb,
1036 NULL,
1037 GNUNET_MQ_hd_var_size (query_message,
1038 GNUNET_MESSAGE_TYPE_REVOCATION_QUERY,
1039 struct QueryMessage,
1040 NULL),
1041 GNUNET_MQ_hd_var_size (revoke_message,
1042 GNUNET_MESSAGE_TYPE_REVOCATION_REVOKE,
1043 struct RevokeMessage,
1044 NULL),
1045 GNUNET_MQ_handler_end ());
1046
1047
1048#if defined(__linux__) && defined(__GLIBC__)
1049#include <malloc.h>
1050
1051/**
1052 * MINIMIZE heap size (way below 128k) since this process doesn't need much.
1053 */
1054void __attribute__ ((constructor))
1055GNUNET_REVOCATION_memory_init ()
1056{
1057 mallopt (M_TRIM_THRESHOLD, 4 * 1024);
1058 mallopt (M_TOP_PAD, 1 * 1024);
1059 malloc_trim (0);
1060}
1061
1062
1063#endif
1064
1065
1066/* end of gnunet-service-revocation.c */
diff --git a/src/service/revocation/meson.build b/src/service/revocation/meson.build
new file mode 100644
index 000000000..57f19f115
--- /dev/null
+++ b/src/service/revocation/meson.build
@@ -0,0 +1,44 @@
1libgnunetrevocation_src = ['revocation_api.c']
2
3gnunetservicerevocation_src = ['gnunet-service-revocation.c']
4
5configure_file(input : 'revocation.conf.in',
6 output : 'revocation.conf',
7 configuration : cdata,
8 install: true,
9 install_dir: pkgcfgdir)
10
11
12if get_option('monolith')
13 foreach p : libgnunetrevocation_src + gnunetservicerevocation_src
14 gnunet_src += 'revocation/' + p
15 endforeach
16endif
17
18libgnunetrevocation = library('gnunetrevocation',
19 libgnunetrevocation_src,
20 soversion: '0',
21 version: '0.0.0',
22 dependencies: [libgnunetutil_dep,
23 libgnunetgnsrecord_dep,
24 libgnunetidentity_dep],
25 include_directories: [incdir, configuration_inc],
26 install: true,
27 install_dir: get_option('libdir'))
28libgnunetrevocation_dep = declare_dependency(link_with : libgnunetrevocation)
29pkg.generate(libgnunetrevocation, url: 'https://www.gnunet.org',
30 description : 'Provides API to perform key revocation in GNUnet')
31
32executable ('gnunet-service-revocation',
33 gnunetservicerevocation_src,
34 dependencies: [libgnunetrevocation_dep,
35 libgnunetutil_dep,
36 libgnunetstatistics_dep,
37 libgnunetcore_dep,
38 libgnunetsetu_dep,
39 libgnunetgnsrecord_dep,
40 libgnunetidentity_dep],
41 include_directories: [incdir, configuration_inc],
42 install: true,
43 install_dir: get_option('libdir')/'gnunet'/'libexec')
44
diff --git a/src/service/revocation/revocation.conf.in b/src/service/revocation/revocation.conf.in
new file mode 100644
index 000000000..d2d7de46e
--- /dev/null
+++ b/src/service/revocation/revocation.conf.in
@@ -0,0 +1,19 @@
1[revocation]
2START_ON_DEMAND = @START_ON_DEMAND@
3IMMEDIATE_START = YES
4@JAVAPORT@PORT = 2112
5HOSTNAME = localhost
6BINARY = gnunet-service-revocation
7ACCEPT_FROM = 127.0.0.1;
8ACCEPT_FROM6 = ::1;
9UNIXPATH = $GNUNET_RUNTIME_DIR/gnunet-service-revocation.sock
10UNIX_MATCH_UID = NO
11UNIX_MATCH_GID = YES
12
13# 2^25 hash operations take about 16-24h on a first-generation i7
14# (using only a single-core) with SCRYPT.
15# DO NOT CHANGE THIS VALUE, doing so will break the protocol!
16WORKBITS = 22
17EPOCH_DURATION = 365 d
18
19DATABASE = $GNUNET_DATA_HOME/revocation.dat
diff --git a/src/service/revocation/revocation.h b/src/service/revocation/revocation.h
new file mode 100644
index 000000000..cbb36acfb
--- /dev/null
+++ b/src/service/revocation/revocation.h
@@ -0,0 +1,115 @@
1/*
2 This file is part of GNUnet.
3 Copyright (C) 2013 GNUnet e.V.
4
5 GNUnet is free software: you can redistribute it and/or modify it
6 under the terms of the GNU Affero General Public License as published
7 by the Free Software Foundation, either version 3 of the License,
8 or (at your 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 Affero General Public License for more details.
14
15 You should have received a copy of the GNU Affero General Public License
16 along with this program. If not, see <http://www.gnu.org/licenses/>.
17
18 SPDX-License-Identifier: AGPL3.0-or-later
19 */
20
21/**
22 * @author Christian Grothoff
23 * @file revocation/revocation.h
24 * @brief messages for key revocation
25 */
26#ifndef REVOCATION_H
27#define REVOCATION_H
28
29#include "gnunet_util_lib.h"
30#include "gnunet_revocation_service.h"
31
32GNUNET_NETWORK_STRUCT_BEGIN
33
34/**
35 * Query key revocation status.
36 */
37struct QueryMessage
38{
39 /**
40 * Type: #GNUNET_MESSAGE_TYPE_REVOCATION_QUERY
41 */
42 struct GNUNET_MessageHeader header;
43
44 /**
45 * Key length.
46 */
47 uint32_t key_len GNUNET_PACKED;
48
49 /**
50 * Followed by the public key to check.
51 */
52};
53
54
55/**
56 * Key revocation response.
57 */
58struct QueryResponseMessage
59{
60 /**
61 * Type: #GNUNET_MESSAGE_TYPE_REVOCATION_QUERY_RESPONSE
62 */
63 struct GNUNET_MessageHeader header;
64
65 /**
66 * #GNUNET_NO if revoked, #GNUNET_YES if valid.
67 */
68 uint32_t is_valid GNUNET_PACKED;
69};
70
71
72/**
73 * Revoke key. These messages are exchanged between peers (during
74 * flooding) but also sent by the client to the service. When the
75 * client sends it to the service, the message is answered by a
76 * #GNUNET_MESSAGE_TYPE_REVOCATION_REVOKE_RESPONSE (which is just
77 * in a `struct GNUNET_MessageHeader`.
78 */
79struct RevokeMessage
80{
81 /**
82 * Type: #GNUNET_MESSAGE_TYPE_REVOCATION_REVOKE
83 */
84 struct GNUNET_MessageHeader header;
85
86 /**
87 * Length of PoW with signature.
88 */
89 uint32_t pow_size GNUNET_PACKED;
90
91 /** Followed by the PoW **/
92};
93
94
95/**
96 * Key revocation response.
97 */
98struct RevocationResponseMessage
99{
100 /**
101 * Type: #GNUNET_MESSAGE_TYPE_REVOCATION_REVOKE_RESPONSE
102 */
103 struct GNUNET_MessageHeader header;
104
105 /**
106 * #GNUNET_NO if revocation failed for internal reasons (e.g. disk full)
107 * #GNUNET_YES on success
108 */
109 uint32_t is_valid GNUNET_PACKED;
110};
111
112
113GNUNET_NETWORK_STRUCT_END
114
115#endif
diff --git a/src/service/revocation/revocation_api.c b/src/service/revocation/revocation_api.c
new file mode 100644
index 000000000..0e3641af8
--- /dev/null
+++ b/src/service/revocation/revocation_api.c
@@ -0,0 +1,334 @@
1/*
2 This file is part of GNUnet
3 Copyright (C) 2013, 2016 GNUnet e.V.
4
5 GNUnet is free software: you can redistribute it and/or modify it
6 under the terms of the GNU Affero General Public License as published
7 by the Free Software Foundation, either version 3 of the License,
8 or (at your 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 Affero General Public License for more details.
14
15 You should have received a copy of the GNU Affero General Public License
16 along with this program. If not, see <http://www.gnu.org/licenses/>.
17
18 SPDX-License-Identifier: AGPL3.0-or-later
19 */
20/**
21 * @file revocation/revocation_api.c
22 * @brief API to perform and access key revocations
23 * @author Christian Grothoff
24 */
25#include "platform.h"
26#include "gnunet_revocation_service.h"
27#include "gnunet_signatures.h"
28#include "gnunet_protocols.h"
29#include "revocation.h"
30#include <inttypes.h>
31
32/**
33 * Handle for the key revocation query.
34 */
35struct GNUNET_REVOCATION_Query
36{
37 /**
38 * Message queue to the service.
39 */
40 struct GNUNET_MQ_Handle *mq;
41
42 /**
43 * Function to call with the result.
44 */
45 GNUNET_REVOCATION_Callback func;
46
47 /**
48 * Closure for @e func.
49 */
50 void *func_cls;
51};
52
53
54/**
55 * Generic error handler, called with the appropriate
56 * error code and the same closure specified at the creation of
57 * the message queue.
58 * Not every message queue implementation supports an error handler.
59 *
60 * @param cls closure with the `struct GNUNET_NSE_Handle *`
61 * @param error error code
62 */
63static void
64query_mq_error_handler (void *cls,
65 enum GNUNET_MQ_Error error)
66{
67 struct GNUNET_REVOCATION_Query *q = cls;
68
69 GNUNET_log (GNUNET_ERROR_TYPE_INFO,
70 "Revocation query MQ error\n");
71 q->func (q->func_cls,
72 GNUNET_SYSERR);
73 GNUNET_REVOCATION_query_cancel (q);
74}
75
76
77/**
78 * Handle response to our revocation query.
79 *
80 * @param cls our `struct GNUNET_REVOCATION_Query` handle
81 * @param qrm response we got
82 */
83static void
84handle_revocation_query_response (void *cls,
85 const struct QueryResponseMessage *qrm)
86{
87 struct GNUNET_REVOCATION_Query *q = cls;
88
89 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
90 "Revocation query result: %d\n",
91 (uint32_t) ntohl (qrm->is_valid));
92 q->func (q->func_cls,
93 ntohl (qrm->is_valid));
94 GNUNET_REVOCATION_query_cancel (q);
95}
96
97
98/**
99 * Check if a key was revoked.
100 *
101 * @param cfg the configuration to use
102 * @param key key to check for revocation
103 * @param func function to call with the result of the check
104 * @param func_cls closure to pass to @a func
105 * @return handle to use in #GNUNET_REVOCATION_query_cancel to stop REVOCATION from invoking the callback
106 */
107struct GNUNET_REVOCATION_Query *
108GNUNET_REVOCATION_query (const struct GNUNET_CONFIGURATION_Handle *cfg,
109 const struct GNUNET_CRYPTO_PublicKey *key,
110 GNUNET_REVOCATION_Callback func,
111 void *func_cls)
112{
113 struct GNUNET_REVOCATION_Query *q
114 = GNUNET_new (struct GNUNET_REVOCATION_Query);
115 struct GNUNET_MQ_MessageHandler handlers[] = {
116 GNUNET_MQ_hd_fixed_size (revocation_query_response,
117 GNUNET_MESSAGE_TYPE_REVOCATION_QUERY_RESPONSE,
118 struct QueryResponseMessage,
119 q),
120 GNUNET_MQ_handler_end ()
121 };
122 struct QueryMessage *qm;
123 struct GNUNET_MQ_Envelope *env;
124 size_t key_len;
125
126 q->mq = GNUNET_CLIENT_connect (cfg,
127 "revocation",
128 handlers,
129 &query_mq_error_handler,
130 q);
131 if (NULL == q->mq)
132 {
133 GNUNET_free (q);
134 return NULL;
135 }
136 q->func = func;
137 q->func_cls = func_cls;
138 key_len = GNUNET_CRYPTO_public_key_get_length (key);
139 env = GNUNET_MQ_msg_extra (qm, key_len,
140 GNUNET_MESSAGE_TYPE_REVOCATION_QUERY);
141 GNUNET_CRYPTO_write_public_key_to_buffer (key, &qm[1], key_len);
142 qm->key_len = htonl (key_len);
143 GNUNET_MQ_send (q->mq,
144 env);
145 return q;
146}
147
148
149/**
150 * Cancel key revocation check.
151 *
152 * @param q query to cancel
153 */
154void
155GNUNET_REVOCATION_query_cancel (struct GNUNET_REVOCATION_Query *q)
156{
157 if (NULL != q->mq)
158 {
159 GNUNET_MQ_destroy (q->mq);
160 q->mq = NULL;
161 }
162 GNUNET_free (q);
163}
164
165
166/**
167 * Handle for the key revocation operation.
168 */
169struct GNUNET_REVOCATION_Handle
170{
171 /**
172 * Message queue to the service.
173 */
174 struct GNUNET_MQ_Handle *mq;
175
176 /**
177 * Function to call once we are done.
178 */
179 GNUNET_REVOCATION_Callback func;
180
181 /**
182 * Closure for @e func.
183 */
184 void *func_cls;
185};
186
187
188/**
189 * Generic error handler, called with the appropriate
190 * error code and the same closure specified at the creation of
191 * the message queue.
192 * Not every message queue implementation supports an error handler.
193 *
194 * @param cls closure with the `struct GNUNET_NSE_Handle *`
195 * @param error error code
196 */
197static void
198revocation_mq_error_handler (void *cls,
199 enum GNUNET_MQ_Error error)
200{
201 struct GNUNET_REVOCATION_Handle *h = cls;
202
203 GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
204 "Revocation MQ error\n");
205 h->func (h->func_cls,
206 GNUNET_SYSERR);
207 GNUNET_REVOCATION_revoke_cancel (h);
208}
209
210
211/**
212 * Handle response to our revocation query.
213 *
214 * @param cls our `struct GNUNET_REVOCATION_Handle` handle
215 * @param rrm response we got
216 */
217static void
218handle_revocation_response (void *cls,
219 const struct RevocationResponseMessage *rrm)
220{
221 struct GNUNET_REVOCATION_Handle *h = cls;
222
223 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
224 "Revocation transmission result: %d\n",
225 (uint32_t) ntohl (rrm->is_valid));
226 h->func (h->func_cls,
227 ntohl (rrm->is_valid));
228 GNUNET_REVOCATION_revoke_cancel (h);
229}
230
231
232/**
233 * Perform key revocation.
234 *
235 * @param cfg the configuration to use
236 * @param key public key of the key to revoke
237 * @param sig signature to use on the revocation (should have been
238 * created using #GNUNET_REVOCATION_sign_revocation).
239 * @param ts revocation timestamp
240 * @param pow proof of work to use (should have been created by
241 * iteratively calling #GNUNET_REVOCATION_check_pow)
242 * @param func function to call with the result of the check
243 * (called with `is_valid` being #GNUNET_NO if
244 * the revocation worked).
245 * @param func_cls closure to pass to @a func
246 * @return handle to use in #GNUNET_REVOCATION_revoke_cancel to stop REVOCATION from invoking the callback
247 */
248struct GNUNET_REVOCATION_Handle *
249GNUNET_REVOCATION_revoke (const struct GNUNET_CONFIGURATION_Handle *cfg,
250 const struct GNUNET_GNSRECORD_PowP *pow,
251 GNUNET_REVOCATION_Callback func,
252 void *func_cls)
253{
254 struct GNUNET_REVOCATION_Handle *h
255 = GNUNET_new (struct GNUNET_REVOCATION_Handle);
256 struct GNUNET_MQ_MessageHandler handlers[] = {
257 GNUNET_MQ_hd_fixed_size (revocation_response,
258 GNUNET_MESSAGE_TYPE_REVOCATION_REVOKE_RESPONSE,
259 struct RevocationResponseMessage,
260 h),
261 GNUNET_MQ_handler_end ()
262 };
263 unsigned long long matching_bits;
264 struct GNUNET_TIME_Relative epoch_duration;
265 struct RevokeMessage *rm;
266 struct GNUNET_MQ_Envelope *env;
267
268 if ((GNUNET_OK !=
269 GNUNET_CONFIGURATION_get_value_number (cfg,
270 "REVOCATION",
271 "WORKBITS",
272 &matching_bits)))
273 {
274 GNUNET_break (0);
275 GNUNET_free (h);
276 return NULL;
277 }
278 if ((GNUNET_OK !=
279 GNUNET_CONFIGURATION_get_value_time (cfg,
280 "REVOCATION",
281 "EPOCH_DURATION",
282 &epoch_duration)))
283 {
284 GNUNET_break (0);
285 GNUNET_free (h);
286 return NULL;
287 }
288 if (GNUNET_YES != GNUNET_GNSRECORD_check_pow (pow,
289 (unsigned int) matching_bits,
290 epoch_duration))
291 {
292 GNUNET_break (0);
293 GNUNET_free (h);
294 return NULL;
295 }
296
297
298 h->mq = GNUNET_CLIENT_connect (cfg,
299 "revocation",
300 handlers,
301 &revocation_mq_error_handler,
302 h);
303 if (NULL == h->mq)
304 {
305 GNUNET_free (h);
306 return NULL;
307 }
308 h->func = func;
309 h->func_cls = func_cls;
310 size_t extra_len = GNUNET_GNSRECORD_proof_get_size (pow);
311 env = GNUNET_MQ_msg_extra (rm,
312 extra_len,
313 GNUNET_MESSAGE_TYPE_REVOCATION_REVOKE);
314 rm->pow_size = htonl (extra_len);
315 memcpy (&rm[1], pow, extra_len);
316 GNUNET_MQ_send (h->mq,
317 env);
318 return h;
319}
320
321
322void
323GNUNET_REVOCATION_revoke_cancel (struct GNUNET_REVOCATION_Handle *h)
324{
325 if (NULL != h->mq)
326 {
327 GNUNET_MQ_destroy (h->mq);
328 h->mq = NULL;
329 }
330 GNUNET_free (h);
331}
332
333
334/* end of revocation_api.c */
diff --git a/src/service/revocation/test_revocation.c b/src/service/revocation/test_revocation.c
new file mode 100644
index 000000000..0fc3ac7e5
--- /dev/null
+++ b/src/service/revocation/test_revocation.c
@@ -0,0 +1,419 @@
1/*
2 This file is part of GNUnet.
3 Copyright (C) 2009, 2013, 2016 GNUnet e.V.
4
5 GNUnet is free software: you can redistribute it and/or modify it
6 under the terms of the GNU Affero General Public License as published
7 by the Free Software Foundation, either version 3 of the License,
8 or (at your 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 Affero General Public License for more details.
14
15 You should have received a copy of the GNU Affero General Public License
16 along with this program. If not, see <http://www.gnu.org/licenses/>.
17
18 SPDX-License-Identifier: AGPL3.0-or-later
19 */
20/**
21 * @file revocation/test_revocation.c
22 * @brief base testcase for revocation exchange
23 * @author Matthias Wachs
24 * @author Christian Grothoff
25 */
26#include "platform.h"
27#include "gnunet_core_service.h"
28#include "gnunet_identity_service.h"
29#include "gnunet_revocation_service.h"
30#include "gnunet_testbed_service.h"
31
32#define NUM_TEST_PEERS 2
33
34struct TestPeer
35{
36 struct GNUNET_TESTBED_Peer *p;
37 struct GNUNET_TESTBED_Operation *identity_op;
38 struct GNUNET_TESTBED_Operation *core_op;
39 struct GNUNET_IDENTITY_Handle *idh;
40 const struct GNUNET_CONFIGURATION_Handle *cfg;
41 const struct GNUNET_CRYPTO_PrivateKey *privkey;
42 struct GNUNET_CRYPTO_PublicKey pubkey;
43 struct GNUNET_CRYPTO_EcdsaSignature sig;
44 struct GNUNET_IDENTITY_Operation *create_id_op;
45 struct GNUNET_IDENTITY_EgoLookup *ego_lookup;
46 struct GNUNET_REVOCATION_Handle *revok_handle;
47 struct GNUNET_CORE_Handle *ch;
48 struct GNUNET_REVOCATION_PowCalculationHandle *pow;
49};
50
51static struct TestPeer testpeers[2];
52
53/**
54 * Return value from main, set to 0 on success.
55 */
56static int ok;
57
58
59static void
60do_shutdown (void *cls)
61{
62 for (unsigned int c = 0; c < NUM_TEST_PEERS; c++)
63 {
64 if (NULL != testpeers[c].create_id_op)
65 {
66 GNUNET_IDENTITY_cancel (testpeers[c].create_id_op);
67 testpeers[c].create_id_op = NULL;
68 }
69 if (NULL != testpeers[c].ego_lookup)
70 {
71 GNUNET_IDENTITY_ego_lookup_cancel (testpeers[c].ego_lookup);
72 testpeers[c].ego_lookup = NULL;
73 }
74 if (NULL != testpeers[c].revok_handle)
75 {
76 GNUNET_REVOCATION_revoke_cancel (testpeers[c].revok_handle);
77 testpeers[c].revok_handle = NULL;
78 }
79 if (NULL != testpeers[c].identity_op)
80 {
81 GNUNET_TESTBED_operation_done (testpeers[c].identity_op);
82 testpeers[c].identity_op = NULL;
83 }
84 if (NULL != testpeers[c].core_op)
85 {
86 GNUNET_TESTBED_operation_done (testpeers[c].core_op);
87 testpeers[c].core_op = NULL;
88 }
89 }
90}
91
92
93static void
94check_revocation (void *cls);
95
96
97static void
98revocation_remote_cb (void *cls, int is_valid)
99{
100 static int repeat = 0;
101
102 if (GNUNET_NO == is_valid)
103 {
104 GNUNET_log (GNUNET_ERROR_TYPE_INFO, "Local revocation successful\n");
105 ok = 0;
106 GNUNET_SCHEDULER_shutdown ();
107 return;
108 }
109 if (repeat < 10)
110 {
111 repeat++;
112 GNUNET_SCHEDULER_add_delayed (GNUNET_TIME_UNIT_SECONDS,
113 &check_revocation,
114 NULL);
115 return;
116 }
117 GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "Flooding of revocation failed\n");
118 ok = 2;
119 GNUNET_SCHEDULER_shutdown ();
120}
121
122
123static void
124check_revocation (void *cls)
125{
126 GNUNET_REVOCATION_query (testpeers[0].cfg,
127 &testpeers[1].pubkey,
128 &revocation_remote_cb,
129 NULL);
130}
131
132
133static void
134revocation_cb (void *cls, enum GNUNET_GenericReturnValue is_valid)
135{
136 testpeers[1].revok_handle = NULL;
137 if (GNUNET_NO == is_valid)
138 {
139 GNUNET_log (GNUNET_ERROR_TYPE_INFO, "Revocation successful\n");
140 check_revocation (NULL);
141 }
142}
143
144
145static struct GNUNET_REVOCATION_PowP *proof_of_work;
146
147static void
148ego_cb (void *cls, struct GNUNET_IDENTITY_Ego *ego)
149{
150 static int completed = 0;
151 const struct GNUNET_CRYPTO_PrivateKey *privkey;
152
153 if ((NULL != ego) && (cls == &testpeers[0]))
154 {
155 testpeers[0].ego_lookup = NULL;
156 testpeers[0].privkey = GNUNET_IDENTITY_ego_get_private_key (ego);
157 GNUNET_IDENTITY_ego_get_public_key (ego, &testpeers[0].pubkey);
158 completed++;
159 }
160 if ((NULL != ego) && (cls == &testpeers[1]))
161 {
162 testpeers[1].ego_lookup = NULL;
163 testpeers[1].privkey = GNUNET_IDENTITY_ego_get_private_key (ego);
164 GNUNET_IDENTITY_ego_get_public_key (ego, &testpeers[1].pubkey);
165 GNUNET_log (GNUNET_ERROR_TYPE_INFO, "Calculating proof of work...\n");
166 privkey = GNUNET_IDENTITY_ego_get_private_key (ego);
167 proof_of_work = GNUNET_malloc (GNUNET_REVOCATION_MAX_PROOF_SIZE);
168 GNUNET_REVOCATION_pow_init (privkey,
169 proof_of_work);
170 testpeers[1].pow = GNUNET_REVOCATION_pow_start (proof_of_work,
171 1,
172 5);
173 int res =
174 GNUNET_REVOCATION_pow_round (testpeers[1].pow);
175 while (GNUNET_OK != res)
176 {
177 res =
178 GNUNET_REVOCATION_pow_round (testpeers[1].pow);
179 }
180 fprintf (stderr, "Done calculating proof of work\n");
181 completed++;
182 }
183 if (2 == completed)
184 {
185 GNUNET_log (GNUNET_ERROR_TYPE_INFO, "Egos retrieved\n");
186 testpeers[1].revok_handle = GNUNET_REVOCATION_revoke (testpeers[1].cfg,
187 proof_of_work,
188 &revocation_cb,
189 NULL);
190 GNUNET_REVOCATION_pow_stop (testpeers[1].pow);
191 }
192}
193
194
195static void
196identity_create_cb (void *cls,
197 const struct GNUNET_CRYPTO_PrivateKey *pk,
198 enum GNUNET_ErrorCode ec)
199{
200 static int completed = 0;
201
202 if ((GNUNET_EC_NONE == ec) && (cls == &testpeers[0]))
203 {
204 testpeers[0].create_id_op = NULL;
205 completed++;
206 }
207 if ((GNUNET_EC_NONE == ec) && (cls == &testpeers[1]))
208 {
209 testpeers[1].create_id_op = NULL;
210 completed++;
211 }
212 if (2 != completed)
213 return;
214 fprintf (stderr, "Identities created\n");
215 testpeers[0].ego_lookup = GNUNET_IDENTITY_ego_lookup (testpeers[0].cfg,
216 "client",
217 &ego_cb,
218 &testpeers[0]);
219 testpeers[1].ego_lookup = GNUNET_IDENTITY_ego_lookup (testpeers[1].cfg,
220 "toberevoked",
221 &ego_cb,
222 &testpeers[1]);
223}
224
225
226static void
227identity_completion_cb (void *cls,
228 struct GNUNET_TESTBED_Operation *op,
229 void *ca_result,
230 const char *emsg)
231{
232 static int completed = 0;
233
234 completed++;
235 if (NUM_TEST_PEERS != completed)
236 return;
237 fprintf (stderr, "All peers connected @ IDENTITY ...\n");
238 testpeers[0].create_id_op = GNUNET_IDENTITY_create (testpeers[0].idh,
239 "client",
240 NULL,
241 GNUNET_PUBLIC_KEY_TYPE_ECDSA,
242 &identity_create_cb,
243 &testpeers[0]);
244 testpeers[1].create_id_op = GNUNET_IDENTITY_create (testpeers[1].idh,
245 "toberevoked",
246 NULL,
247 GNUNET_PUBLIC_KEY_TYPE_ECDSA,
248 &identity_create_cb,
249 &testpeers[1]);
250}
251
252
253static void *
254identity_connect_adapter (void *cls,
255 const struct GNUNET_CONFIGURATION_Handle *cfg)
256{
257 struct TestPeer *me = cls;
258
259 me->cfg = cfg;
260 me->idh = GNUNET_IDENTITY_connect (cfg, NULL, NULL);
261 if (NULL == me->idh)
262 GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "Failed to create IDENTITY handle \n");
263 return me->idh;
264}
265
266
267static void
268identity_disconnect_adapter (void *cls, void *op_result)
269{
270 struct TestPeer *me = cls;
271
272 GNUNET_IDENTITY_disconnect (me->idh);
273 me->idh = NULL;
274}
275
276
277static void *
278connect_cb (void *cls,
279 const struct GNUNET_PeerIdentity *peer,
280 struct GNUNET_MQ_Handle *mq)
281{
282 static int connects = 0;
283
284 connects++;
285 if (NUM_TEST_PEERS * NUM_TEST_PEERS == connects)
286 {
287 fprintf (stderr, "All peers connected @ CORE ...\n");
288
289 /* Connect to identity service */
290 testpeers[0].identity_op =
291 GNUNET_TESTBED_service_connect (NULL,
292 testpeers[0].p,
293 "identity",
294 &identity_completion_cb,
295 NULL,
296 &identity_connect_adapter,
297 &identity_disconnect_adapter,
298 &testpeers[0]);
299 testpeers[1].identity_op =
300 GNUNET_TESTBED_service_connect (NULL,
301 testpeers[1].p,
302 "identity",
303 *identity_completion_cb,
304 NULL,
305 &identity_connect_adapter,
306 &identity_disconnect_adapter,
307 &testpeers[1]);
308 }
309 return NULL;
310}
311
312
313static void
314core_completion_cb (void *cls,
315 struct GNUNET_TESTBED_Operation *op,
316 void *ca_result,
317 const char *emsg)
318{
319 static int completed = 0;
320
321 completed++;
322 if (NUM_TEST_PEERS == completed)
323 {
324 GNUNET_log (GNUNET_ERROR_TYPE_INFO, "Connected to CORE\n");
325 }
326}
327
328
329static void *
330core_connect_adapter (void *cls, const struct GNUNET_CONFIGURATION_Handle *cfg)
331{
332 struct TestPeer *me = cls;
333
334 me->cfg = cfg;
335 me->ch = GNUNET_CORE_connect (cfg, me, NULL, &connect_cb, NULL, NULL);
336 if (NULL == me->ch)
337 GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "Failed to create CORE handle \n");
338 return me->ch;
339}
340
341
342static void
343core_disconnect_adapter (void *cls, void *op_result)
344{
345 struct TestPeer *me = cls;
346
347 GNUNET_CORE_disconnect (me->ch);
348 me->ch = NULL;
349}
350
351
352static void
353test_connection (void *cls,
354 struct GNUNET_TESTBED_RunHandle *h,
355 unsigned int num_peers,
356 struct GNUNET_TESTBED_Peer **peers,
357 unsigned int links_succeeded,
358 unsigned int links_failed)
359{
360 unsigned int c;
361
362 GNUNET_SCHEDULER_add_shutdown (&do_shutdown, NULL);
363 if (NUM_TEST_PEERS != num_peers)
364 {
365 ok = 4;
366 fprintf (stderr,
367 "Only %u out of %u peers were started ...\n",
368 num_peers,
369 NUM_TEST_PEERS);
370 GNUNET_SCHEDULER_shutdown ();
371 return;
372 }
373 /* We are generating a CLIQUE */
374 if (NUM_TEST_PEERS * (NUM_TEST_PEERS - 1) == links_succeeded)
375 {
376 GNUNET_log (GNUNET_ERROR_TYPE_INFO,
377 "Testbed connected peers, initializing test\n");
378 for (c = 0; c < num_peers; c++)
379 {
380 testpeers[c].p = peers[c];
381 testpeers[c].core_op =
382 GNUNET_TESTBED_service_connect (NULL,
383 testpeers[c].p,
384 "core",
385 &core_completion_cb,
386 NULL,
387 &core_connect_adapter,
388 &core_disconnect_adapter,
389 &testpeers[c]);
390 }
391 }
392 else
393 {
394 GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "Testbed failed to connect peers\n");
395 ok = 5;
396 GNUNET_SCHEDULER_shutdown ();
397 return;
398 }
399}
400
401
402int
403main (int argc, char *argv[])
404{
405 ok = 1;
406 /* Connecting initial topology */
407 (void) GNUNET_TESTBED_test_run ("test-revocation",
408 "test_revocation.conf",
409 NUM_TEST_PEERS,
410 0,
411 NULL,
412 NULL,
413 &test_connection,
414 NULL);
415 return ok;
416}
417
418
419/* end of test_revocation.c */
diff --git a/src/service/revocation/test_revocation.conf b/src/service/revocation/test_revocation.conf
new file mode 100644
index 000000000..f852d38c3
--- /dev/null
+++ b/src/service/revocation/test_revocation.conf
@@ -0,0 +1,31 @@
1@INLINE@ ../../../contrib/conf/gnunet/no_forcestart.conf
2
3[paths]
4GNUNET_HOME=$GNUNET_TMP/test-revocation-service
5SERVICEHOME=$GNUNET_TMP/test-revocation-service
6
7[revocation]
8WORKBITS = 3
9IMMEDIATE_START = YES
10EPOCH_DURATION = 365 d
11
12[identity]
13# Directory where we store information about our egos
14EGODIR = $GNUNET_HOME/identity/egos/
15SUBSYSTEM_CFG = $SERVICEHOME/s.conf
16
17[nat]
18RETURN_LOCAL_ADDRESSES = YES
19
20[transport]
21PLUGINS = tcp
22
23[peerinfo]
24USE_INCLUDED_HELLOS = NO
25
26[testbed]
27OVERLAY_TOPOLOGY = CLIQUE
28SETUP_TIMEOUT = 10 s
29OPERATION_TIMEOUT = 5 s
30CACHE_SIZE = 0
31
diff --git a/src/service/revocation/test_revocation_testvectors.c b/src/service/revocation/test_revocation_testvectors.c
new file mode 100644
index 000000000..a669e1b7e
--- /dev/null
+++ b/src/service/revocation/test_revocation_testvectors.c
@@ -0,0 +1,297 @@
1#include "platform.h"
2#include "gnunet_util_lib.h"
3#include "gnunet_revocation_service.h"
4#include "gnunet_gnsrecord_lib.h"
5#include <inttypes.h>
6
7int res;
8
9struct RevocationTv
10{
11 char *d;
12 char *zid;
13 char *ztld;
14 char *m;
15 char *proof;
16 int diff;
17 int epochs;
18};
19
20struct RevocationTv rtvs[] = {
21 {
22 .d =
23 "6f ea 32 c0 5a f5 8b fa"
24 "97 95 53 d1 88 60 5f d5"
25 "7d 8b f9 cc 26 3b 78 d5"
26 "f7 47 8c 07 b9 98 ed 70",
27 .zid =
28 "00 01 00 00 2c a2 23 e8"
29 "79 ec c4 bb de b5 da 17"
30 "31 92 81 d6 3b 2e 3b 69"
31 "55 f1 c3 77 5c 80 4a 98"
32 "d5 f8 dd aa",
33 .ztld =
34 "000G001CM8HYGYFCRJXXXDET2WRS50EP7CQ3PTANY71QEQ409ACDBY6XN8",
35 .m =
36 "00 00 00 34 00 00 00 03"
37 "00 05 fe b4 6d 86 5c 1c"
38 "00 01 00 00 2c a2 23 e8"
39 "79 ec c4 bb de b5 da 17"
40 "31 92 81 d6 3b 2e 3b 69"
41 "55 f1 c3 77 5c 80 4a 98"
42 "d5 f8 dd aa",
43 .proof =
44 "00 05 ff 1c 56 e4 b2 68"
45 "00 00 39 5d 18 27 c0 00"
46 "38 0b 54 aa 70 16 ac a2"
47 "38 0b 54 aa 70 16 ad 62"
48 "38 0b 54 aa 70 16 af 3e"
49 "38 0b 54 aa 70 16 af 93"
50 "38 0b 54 aa 70 16 b0 bf"
51 "38 0b 54 aa 70 16 b0 ee"
52 "38 0b 54 aa 70 16 b1 c9"
53 "38 0b 54 aa 70 16 b1 e5"
54 "38 0b 54 aa 70 16 b2 78"
55 "38 0b 54 aa 70 16 b2 b2"
56 "38 0b 54 aa 70 16 b2 d6"
57 "38 0b 54 aa 70 16 b2 e4"
58 "38 0b 54 aa 70 16 b3 2c"
59 "38 0b 54 aa 70 16 b3 5a"
60 "38 0b 54 aa 70 16 b3 9d"
61 "38 0b 54 aa 70 16 b3 c0"
62 "38 0b 54 aa 70 16 b3 dd"
63 "38 0b 54 aa 70 16 b3 f4"
64 "38 0b 54 aa 70 16 b4 42"
65 "38 0b 54 aa 70 16 b4 76"
66 "38 0b 54 aa 70 16 b4 8c"
67 "38 0b 54 aa 70 16 b4 a4"
68 "38 0b 54 aa 70 16 b4 c9"
69 "38 0b 54 aa 70 16 b4 f0"
70 "38 0b 54 aa 70 16 b4 f7"
71 "38 0b 54 aa 70 16 b5 79"
72 "38 0b 54 aa 70 16 b6 34"
73 "38 0b 54 aa 70 16 b6 8e"
74 "38 0b 54 aa 70 16 b7 b4"
75 "38 0b 54 aa 70 16 b8 7e"
76 "38 0b 54 aa 70 16 b8 f8"
77 "38 0b 54 aa 70 16 b9 2a"
78 "00 01 00 00 2c a2 23 e8"
79 "79 ec c4 bb de b5 da 17"
80 "31 92 81 d6 3b 2e 3b 69"
81 "55 f1 c3 77 5c 80 4a 98"
82 "d5 f8 dd aa 08 ca ff de"
83 "3c 6d f1 45 f7 e0 79 81"
84 "15 37 b2 b0 42 2d 5e 1f"
85 "b2 01 97 81 ec a2 61 d1"
86 "f9 d8 ea 81 0a bc 2f 33"
87 "47 7f 04 e3 64 81 11 be"
88 "71 c2 48 82 1a d6 04 f4"
89 "94 e7 4d 0b f5 11 d2 c1"
90 "62 77 2e 81",
91 .diff = 5,
92 .epochs = 2
93 },
94 {
95 .d =
96 "5a f7 02 0e e1 91 60 32"
97 "88 32 35 2b bc 6a 68 a8"
98 "d7 1a 7c be 1b 92 99 69"
99 "a7 c6 6d 41 5a 0d 8f 65",
100 .zid =
101 "00 01 00 14 3c f4 b9 24"
102 "03 20 22 f0 dc 50 58 14"
103 "53 b8 5d 93 b0 47 b6 3d"
104 "44 6c 58 45 cb 48 44 5d"
105 "db 96 68 8f",
106 .ztld =
107 "000G051WYJWJ80S04BRDRM2R2H9VGQCKP13VCFA4DHC4BJT88HEXQ5K8HW",
108 .diff = 5,
109 .epochs = 2,
110 .m =
111 "00 00 00 34 00 00 00 03"
112 "00 05 ff 1c 57 35 42 bd"
113 "00 01 00 14 3c f4 b9 24"
114 "03 20 22 f0 dc 50 58 14"
115 "53 b8 5d 93 b0 47 b6 3d"
116 "44 6c 58 45 cb 48 44 5d"
117 "db 96 68 8f",
118 .proof =
119 "00 05 ff 1c 57 35 42 bd"
120 "00 00 39 5d 18 27 c0 00"
121 "58 4c 93 3c b0 99 2a 08"
122 "58 4c 93 3c b0 99 2d f7"
123 "58 4c 93 3c b0 99 2e 21"
124 "58 4c 93 3c b0 99 2e 2a"
125 "58 4c 93 3c b0 99 2e 53"
126 "58 4c 93 3c b0 99 2e 8e"
127 "58 4c 93 3c b0 99 2f 13"
128 "58 4c 93 3c b0 99 2f 2d"
129 "58 4c 93 3c b0 99 2f 3c"
130 "58 4c 93 3c b0 99 2f 41"
131 "58 4c 93 3c b0 99 2f fd"
132 "58 4c 93 3c b0 99 30 33"
133 "58 4c 93 3c b0 99 30 82"
134 "58 4c 93 3c b0 99 30 a2"
135 "58 4c 93 3c b0 99 30 e1"
136 "58 4c 93 3c b0 99 31 ce"
137 "58 4c 93 3c b0 99 31 de"
138 "58 4c 93 3c b0 99 32 12"
139 "58 4c 93 3c b0 99 32 4e"
140 "58 4c 93 3c b0 99 32 9f"
141 "58 4c 93 3c b0 99 33 31"
142 "58 4c 93 3c b0 99 33 87"
143 "58 4c 93 3c b0 99 33 8c"
144 "58 4c 93 3c b0 99 33 e5"
145 "58 4c 93 3c b0 99 33 f3"
146 "58 4c 93 3c b0 99 34 26"
147 "58 4c 93 3c b0 99 34 30"
148 "58 4c 93 3c b0 99 34 68"
149 "58 4c 93 3c b0 99 34 88"
150 "58 4c 93 3c b0 99 34 8a"
151 "58 4c 93 3c b0 99 35 4c"
152 "58 4c 93 3c b0 99 35 bd"
153 "00 01 00 14 3c f4 b9 24"
154 "03 20 22 f0 dc 50 58 14"
155 "53 b8 5d 93 b0 47 b6 3d"
156 "44 6c 58 45 cb 48 44 5d"
157 "db 96 68 8f 04 ae 26 f7"
158 "63 56 5a b7 aa ab 01 71"
159 "72 4f 3c a8 bc c5 1a 98"
160 "b7 d4 c9 2e a3 3c d9 34"
161 "4c a8 b6 3e 04 53 3a bf"
162 "1a 3c 05 49 16 b3 68 2c"
163 "5c a8 cb 4d d0 f8 4c 3b"
164 "77 48 7a ac 6e ce 38 48"
165 "0b a9 d5 00"
166 },
167 { .d = NULL }
168};
169
170static void
171print_bytes_ (void *buf,
172 size_t buf_len,
173 int fold,
174 int in_be)
175{
176 int i;
177
178 for (i = 0; i < buf_len; i++)
179 {
180 if (0 != i)
181 {
182 if ((0 != fold) && (i % fold == 0))
183 printf ("\n ");
184 else
185 printf (" ");
186 }
187 else
188 {
189 printf (" ");
190 }
191 if (in_be)
192 printf ("%02x", ((unsigned char*) buf)[buf_len - 1 - i]);
193 else
194 printf ("%02x", ((unsigned char*) buf)[i]);
195 }
196 printf ("\n");
197}
198
199
200static void
201print_bytes (void *buf,
202 size_t buf_len,
203 int fold)
204{
205 print_bytes_ (buf, buf_len, fold, 0);
206}
207
208
209int
210parsehex (char *src, char *dst, size_t dstlen, int invert)
211{
212 int off;
213 int read_byte;
214 int data_len = 0;
215 char data[strlen (src) + 1];
216 char *pos = data;
217 int i = 0;
218 int j = 0;
219
220 for (i = 0; i < strlen (src); i++)
221 {
222 if ((src[i] == ' ') || (src[i] == '\n'))
223 continue;
224 data[j++] = src[i];
225 }
226
227 while (sscanf (pos, " %02x%n", &read_byte, &off) == 1)
228 {
229 if (invert)
230 dst[dstlen - 1 - data_len++] = read_byte;
231 else
232 dst[data_len++] = read_byte;
233 pos += off;
234 }
235 return data_len;
236}
237
238
239int
240main ()
241{
242 struct GNUNET_CRYPTO_PrivateKey priv;
243 struct GNUNET_CRYPTO_PublicKey pub;
244 struct GNUNET_CRYPTO_PublicKey pub_parsed;
245 struct GNUNET_TIME_Relative exprel;
246 struct GNUNET_REVOCATION_PowP *pow;
247 char m[8096];
248 char ztld[128];
249 res = 0;
250
251 for (int i = 0; NULL != rtvs[i].d; i++)
252 {
253 printf ("Revocation test vector #%d\n", i);
254 parsehex (rtvs[i].zid,(char*) &pub_parsed, 36, 0);
255 parsehex (rtvs[i].d,(char*) &priv.ecdsa_key, sizeof (priv.ecdsa_key),
256 (GNUNET_GNSRECORD_TYPE_PKEY == ntohl (pub_parsed.type)) ? 1 : 0);
257 priv.type = pub_parsed.type;
258 GNUNET_CRYPTO_key_get_public (&priv, &pub);
259 if (0 != memcmp (&pub, &pub_parsed, GNUNET_CRYPTO_public_key_get_length (
260 &pub)))
261 {
262 printf ("Wrong pubkey.\n");
263 print_bytes (&pub, 36, 8);
264 print_bytes (&pub_parsed, 36, 8);
265 res = 1;
266 break;
267 }
268 GNUNET_STRINGS_data_to_string (&pub,
269 GNUNET_CRYPTO_public_key_get_length (
270 &pub),
271 ztld,
272 sizeof (ztld));
273 if (0 != strcmp (ztld, rtvs[i].ztld))
274 {
275 printf ("Wrong zTLD: expected %s, got %s\n", rtvs[i].ztld, ztld);
276 res = 1;
277 break;
278 }
279 pow = GNUNET_malloc (GNUNET_REVOCATION_MAX_PROOF_SIZE);
280 parsehex (rtvs[i].proof, (char*) pow, 0, 0);
281 // parsehex (rtvs[i].m, (char*) message, 0, 0);
282
283 exprel = GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_YEARS,
284 rtvs[i].epochs);
285 if (GNUNET_OK != GNUNET_REVOCATION_check_pow (pow, rtvs[i].diff,
286 exprel))
287 {
288 printf ("FAIL: Revocation PoW invalid\n");
289 res = 1;
290 break;
291 }
292 printf ("Good.\n");
293 }
294
295finish:
296 return res;
297}