aboutsummaryrefslogtreecommitdiff
path: root/src/service
diff options
context:
space:
mode:
Diffstat (limited to 'src/service')
-rw-r--r--src/service/Makefile.am4
-rw-r--r--src/service/revocation/.gitignore5
-rw-r--r--src/service/revocation/Makefile.am74
-rw-r--r--src/service/revocation/gnunet-service-revocation.c1064
-rw-r--r--src/service/revocation/meson.build63
-rw-r--r--src/service/revocation/revocation.conf.in19
-rw-r--r--src/service/revocation/revocation.h124
-rw-r--r--src/service/revocation/revocation_api.c764
-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
11 files changed, 2863 insertions, 1 deletions
diff --git a/src/service/Makefile.am b/src/service/Makefile.am
index e39b28ae9..52dec5726 100644
--- a/src/service/Makefile.am
+++ b/src/service/Makefile.am
@@ -22,4 +22,6 @@ SUBDIRS = \
22 cadet \ 22 cadet \
23 seti \ 23 seti \
24 setu \ 24 setu \
25 regex 25 regex \
26 revocation
27
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..726c75ab6
--- /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/service/identity/libgnunetidentity.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/service/identity/libgnunetidentity.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..3755b87e5
--- /dev/null
+++ b/src/service/revocation/gnunet-service-revocation.c
@@ -0,0 +1,1064 @@
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_block_lib.h"
42#include "gnunet_constants.h"
43#include "gnunet_protocols.h"
44#include "gnunet_signatures.h"
45#include "gnunet_statistics_service.h"
46#include "gnunet_core_service.h"
47#include "gnunet_revocation_service.h"
48#include "gnunet_setu_service.h"
49#include "revocation.h"
50#include <gcrypt.h>
51
52
53/**
54 * Per-peer information.
55 */
56struct PeerEntry
57{
58 /**
59 * Queue for sending messages to this peer.
60 */
61 struct GNUNET_MQ_Handle *mq;
62
63 /**
64 * What is the identity of the peer?
65 */
66 struct GNUNET_PeerIdentity id;
67
68 /**
69 * Tasked used to trigger the set union operation.
70 */
71 struct GNUNET_SCHEDULER_Task *transmit_task;
72
73 /**
74 * Handle to active set union operation (over revocation sets).
75 */
76 struct GNUNET_SETU_OperationHandle *so;
77};
78
79
80/**
81 * Set from all revocations known to us.
82 */
83static struct GNUNET_SETU_Handle *revocation_set;
84
85/**
86 * Hash map with all revoked keys, maps the hash of the public key
87 * to the respective `struct RevokeMessage`.
88 */
89static struct GNUNET_CONTAINER_MultiHashMap *revocation_map;
90
91/**
92 * Handle to our current configuration.
93 */
94static const struct GNUNET_CONFIGURATION_Handle *cfg;
95
96/**
97 * Handle to the statistics service.
98 */
99static struct GNUNET_STATISTICS_Handle *stats;
100
101/**
102 * Handle to the core service (for flooding)
103 */
104static struct GNUNET_CORE_Handle *core_api;
105
106/**
107 * Map of all connected peers.
108 */
109static struct GNUNET_CONTAINER_MultiPeerMap *peers;
110
111/**
112 * The peer identity of this peer.
113 */
114static struct GNUNET_PeerIdentity my_identity;
115
116/**
117 * File handle for the revocation database.
118 */
119static struct GNUNET_DISK_FileHandle *revocation_db;
120
121/**
122 * Handle for us listening to incoming revocation set union requests.
123 */
124static struct GNUNET_SETU_ListenHandle *revocation_union_listen_handle;
125
126/**
127 * Amount of work required (W-bit collisions) for REVOCATION proofs, in collision-bits.
128 */
129static unsigned long long revocation_work_required;
130
131/**
132 * Length of an expiration expoch
133 */
134static struct GNUNET_TIME_Relative epoch_duration;
135
136/**
137 * Our application ID for set union operations. Must be the
138 * same for all (compatible) peers.
139 */
140static struct GNUNET_HashCode revocation_set_union_app_id;
141
142
143/**
144 * Create a new PeerEntry and add it to the peers multipeermap.
145 *
146 * @param peer the peer identity
147 * @return a pointer to the new PeerEntry
148 */
149static struct PeerEntry *
150new_peer_entry (const struct GNUNET_PeerIdentity *peer)
151{
152 struct PeerEntry *peer_entry;
153
154 peer_entry = GNUNET_new (struct PeerEntry);
155 peer_entry->id = *peer;
156 GNUNET_assert (GNUNET_OK ==
157 GNUNET_CONTAINER_multipeermap_put (peers,
158 &peer_entry->id,
159 peer_entry,
160 GNUNET_CONTAINER_MULTIHASHMAPOPTION_UNIQUE_ONLY));
161 return peer_entry;
162}
163
164
165/**
166 * An revoke message has been received, check that it is well-formed.
167 *
168 * @param rm the message to verify
169 * @return #GNUNET_YES if the message is verified
170 * #GNUNET_NO if the key/signature don't verify
171 */
172static enum GNUNET_GenericReturnValue
173verify_revoke_message (const struct RevokeMessage *rm)
174{
175 const struct GNUNET_REVOCATION_PowP *pow
176 = (const struct GNUNET_REVOCATION_PowP *) &rm[1];
177
178 if (GNUNET_YES !=
179 GNUNET_REVOCATION_check_pow (pow,
180 (unsigned int) revocation_work_required,
181 epoch_duration))
182 {
183 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
184 "Proof of work invalid!\n");
185 GNUNET_break_op (0);
186 return GNUNET_NO;
187 }
188 return GNUNET_YES;
189}
190
191
192/**
193 * Handle client connecting to the service.
194 *
195 * @param cls NULL
196 * @param client the new client
197 * @param mq the message queue of @a client
198 * @return @a client
199 */
200static void *
201client_connect_cb (void *cls,
202 struct GNUNET_SERVICE_Client *client,
203 struct GNUNET_MQ_Handle *mq)
204{
205 return client;
206}
207
208
209/**
210 * Handle client connecting to the service.
211 *
212 * @param cls NULL
213 * @param client the new client
214 * @param app_cls must alias @a client
215 */
216static void
217client_disconnect_cb (void *cls,
218 struct GNUNET_SERVICE_Client *client,
219 void *app_cls)
220{
221 GNUNET_assert (client == app_cls);
222}
223
224static int
225check_query_message (void *cls,
226 const struct QueryMessage *qm)
227{
228 uint16_t size;
229
230 size = ntohs (qm->header.size);
231 if (size <= sizeof(struct RevokeMessage) ||
232 (size > UINT16_MAX))
233 {
234 GNUNET_break (0);
235 return GNUNET_SYSERR;
236 }
237 return GNUNET_OK;
238
239}
240
241
242/**
243 * Handle QUERY message from client.
244 *
245 * @param cls client who sent the message
246 * @param qm the message received
247 */
248static void
249handle_query_message (void *cls,
250 const struct QueryMessage *qm)
251{
252 struct GNUNET_SERVICE_Client *client = cls;
253 struct GNUNET_CRYPTO_PublicKey zone;
254 struct GNUNET_MQ_Envelope *env;
255 struct QueryResponseMessage *qrm;
256 struct GNUNET_HashCode hc;
257 int res;
258 size_t key_len;
259 size_t read;
260
261 key_len = ntohl (qm->key_len);
262 if ((GNUNET_SYSERR ==
263 GNUNET_CRYPTO_read_public_key_from_buffer (&qm[1], key_len,
264 &zone, &read)) ||
265 (read != key_len))
266 {
267 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
268 "Unable to parse query public key\n");
269 GNUNET_SERVICE_client_drop (client);
270 return;
271 }
272 GNUNET_CRYPTO_hash (&qm[1],
273 key_len,
274 &hc);
275 res = GNUNET_CONTAINER_multihashmap_contains (revocation_map,
276 &hc);
277 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
278 (GNUNET_NO == res)
279 ? "Received revocation check for valid key `%s' from client\n"
280 : "Received revocation check for revoked key `%s' from client\n",
281 GNUNET_h2s (&hc));
282 env = GNUNET_MQ_msg (qrm,
283 GNUNET_MESSAGE_TYPE_REVOCATION_QUERY_RESPONSE);
284 qrm->is_valid = htonl ((GNUNET_YES == res) ? GNUNET_NO : GNUNET_YES);
285 GNUNET_MQ_send (GNUNET_SERVICE_client_get_mq (client),
286 env);
287 GNUNET_SERVICE_client_continue (client);
288}
289
290
291/**
292 * Flood the given revocation message to all neighbours.
293 *
294 * @param cls the `struct RevokeMessage` to flood
295 * @param target a neighbour
296 * @param value our `struct PeerEntry` for the neighbour
297 * @return #GNUNET_OK (continue to iterate)
298 */
299static enum GNUNET_GenericReturnValue
300do_flood (void *cls,
301 const struct GNUNET_PeerIdentity *target,
302 void *value)
303{
304 const struct RevokeMessage *rm = cls;
305 struct PeerEntry *pe = value;
306 struct GNUNET_MQ_Envelope *e;
307 struct RevokeMessage *cp;
308
309 if (NULL == pe->mq)
310 return GNUNET_OK; /* peer connected to us via SET,
311 but we have no direct CORE
312 connection for flooding */
313 e = GNUNET_MQ_msg_extra (cp,
314 htonl (rm->pow_size),
315 GNUNET_MESSAGE_TYPE_REVOCATION_REVOKE);
316 *cp = *rm;
317 memcpy (&cp[1],
318 &rm[1],
319 htonl (rm->pow_size));
320 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
321 "Flooding revocation to `%s'\n",
322 GNUNET_i2s (target));
323 GNUNET_MQ_send (pe->mq,
324 e);
325 return GNUNET_OK;
326}
327
328
329/**
330 * Publicize revocation message. Stores the message locally in the
331 * database and passes it to all connected neighbours (and adds it to
332 * the set for future connections).
333 *
334 * @param rm message to publicize
335 * @return #GNUNET_OK on success, #GNUNET_NO if we encountered an error,
336 * #GNUNET_SYSERR if the message was malformed
337 */
338static enum GNUNET_GenericReturnValue
339publicize_rm (const struct RevokeMessage *rm)
340{
341 struct RevokeMessage *cp;
342 struct GNUNET_HashCode hc;
343 struct GNUNET_SETU_Element e;
344 ssize_t pklen;
345 const struct GNUNET_REVOCATION_PowP *pow
346 = (const struct GNUNET_REVOCATION_PowP *) &rm[1];
347 const struct GNUNET_CRYPTO_PublicKey *pk
348 = (const struct GNUNET_CRYPTO_PublicKey *) &pow[1];
349
350 /** FIXME yeah this works, but should we have a key length somewhere? */
351 pklen = GNUNET_CRYPTO_public_key_get_length (pk);
352 if (0 > pklen)
353 {
354 GNUNET_break_op (0);
355 return GNUNET_SYSERR;
356 }
357 GNUNET_CRYPTO_hash (pk,
358 pklen,
359 &hc);
360 if (GNUNET_YES ==
361 GNUNET_CONTAINER_multihashmap_contains (revocation_map,
362 &hc))
363 {
364 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
365 "Duplicate revocation received from peer. Ignored.\n");
366 return GNUNET_OK;
367 }
368 if (GNUNET_OK !=
369 verify_revoke_message (rm))
370 {
371 GNUNET_break_op (0);
372 return GNUNET_SYSERR;
373 }
374 /* write to disk */
375 if (sizeof(struct RevokeMessage) !=
376 GNUNET_DISK_file_write (revocation_db,
377 rm,
378 sizeof(struct RevokeMessage)))
379 {
380 GNUNET_log_strerror (GNUNET_ERROR_TYPE_ERROR,
381 "write");
382 return GNUNET_NO;
383 }
384 if (GNUNET_OK !=
385 GNUNET_DISK_file_sync (revocation_db))
386 {
387 GNUNET_log_strerror (GNUNET_ERROR_TYPE_ERROR,
388 "sync");
389 return GNUNET_NO;
390 }
391 /* keep copy in memory */
392 cp = (struct RevokeMessage *) GNUNET_copy_message (&rm->header);
393 GNUNET_break (GNUNET_OK ==
394 GNUNET_CONTAINER_multihashmap_put (revocation_map,
395 &hc,
396 cp,
397 GNUNET_CONTAINER_MULTIHASHMAPOPTION_UNIQUE_ONLY));
398 /* add to set for future connections */
399 e.size = htons (rm->header.size);
400 e.element_type = GNUNET_BLOCK_TYPE_REVOCATION;
401 e.data = rm;
402 if (GNUNET_OK !=
403 GNUNET_SETU_add_element (revocation_set,
404 &e,
405 NULL,
406 NULL))
407 {
408 GNUNET_break (0);
409 return GNUNET_OK;
410 }
411 else
412 {
413 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
414 "Added revocation info to SET\n");
415 }
416 /* flood to neighbours */
417 GNUNET_CONTAINER_multipeermap_iterate (peers,
418 &do_flood,
419 cp);
420 return GNUNET_OK;
421}
422
423
424static int
425check_revoke_message (void *cls,
426 const struct RevokeMessage *rm)
427{
428 uint16_t size;
429
430 size = ntohs (rm->header.size);
431 if (size <= sizeof(struct RevokeMessage) ||
432 (size > UINT16_MAX))
433 {
434 GNUNET_break (0);
435 return GNUNET_SYSERR;
436 }
437 return GNUNET_OK;
438
439}
440
441
442/**
443 * Handle REVOKE message from client.
444 *
445 * @param cls client who sent the message
446 * @param rm the message received
447 */
448static void
449handle_revoke_message (void *cls,
450 const struct RevokeMessage *rm)
451{
452 struct GNUNET_SERVICE_Client *client = cls;
453 struct GNUNET_MQ_Envelope *env;
454 struct RevocationResponseMessage *rrm;
455 int ret;
456
457 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
458 "Received REVOKE message from client\n");
459 if (GNUNET_SYSERR == (ret = publicize_rm (rm)))
460 {
461 GNUNET_break_op (0);
462 GNUNET_SERVICE_client_drop (client);
463 return;
464 }
465 env = GNUNET_MQ_msg (rrm,
466 GNUNET_MESSAGE_TYPE_REVOCATION_REVOKE_RESPONSE);
467 rrm->is_valid = htonl ((GNUNET_OK == ret) ? GNUNET_NO : GNUNET_YES);
468 GNUNET_MQ_send (GNUNET_SERVICE_client_get_mq (client),
469 env);
470 GNUNET_SERVICE_client_continue (client);
471}
472
473
474static int
475check_p2p_revoke (void *cls,
476 const struct RevokeMessage *rm)
477{
478 uint16_t size;
479
480 size = ntohs (rm->header.size);
481 if (size <= sizeof(struct RevokeMessage))
482 {
483 GNUNET_break (0);
484 return GNUNET_SYSERR;
485 }
486 return GNUNET_OK;
487
488}
489
490
491/**
492 * Core handler for flooded revocation messages.
493 *
494 * @param cls closure unused
495 * @param rm revocation message
496 */
497static void
498handle_p2p_revoke (void *cls,
499 const struct RevokeMessage *rm)
500{
501 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
502 "Received REVOKE message\n");
503 GNUNET_break_op (GNUNET_SYSERR !=
504 publicize_rm (rm));
505}
506
507
508/**
509 * Callback for set operation results. Called for each element in the
510 * result set. Each element contains a revocation, which we should
511 * validate and then add to our revocation list (and set).
512 *
513 * @param cls closure
514 * @param element a result element, only valid if status is #GNUNET_SETU_STATUS_OK
515 * @param current_size current set size
516 * @param status see `enum GNUNET_SETU_Status`
517 */
518static void
519add_revocation (void *cls,
520 const struct GNUNET_SETU_Element *element,
521 uint64_t current_size,
522 enum GNUNET_SETU_Status status)
523{
524 struct PeerEntry *peer_entry = cls;
525 const struct RevokeMessage *rm;
526
527 switch (status)
528 {
529 case GNUNET_SETU_STATUS_ADD_LOCAL:
530 if (element->size != sizeof(struct RevokeMessage))
531 {
532 GNUNET_break_op (0);
533 return;
534 }
535 if (GNUNET_BLOCK_TYPE_REVOCATION != element->element_type)
536 {
537 GNUNET_STATISTICS_update (stats,
538 gettext_noop (
539 "# unsupported revocations received via set union"),
540 1,
541 GNUNET_NO);
542 return;
543 }
544 rm = element->data;
545 (void) handle_p2p_revoke (NULL,
546 rm);
547 GNUNET_STATISTICS_update (stats,
548 gettext_noop (
549 "# revocation messages received via set union"),
550 1, GNUNET_NO);
551 break;
552 case GNUNET_SETU_STATUS_FAILURE:
553 GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
554 _ ("Error computing revocation set union with %s\n"),
555 GNUNET_i2s (&peer_entry->id));
556 peer_entry->so = NULL;
557 GNUNET_STATISTICS_update (stats,
558 gettext_noop ("# revocation set unions failed"),
559 1,
560 GNUNET_NO);
561 break;
562 case GNUNET_SETU_STATUS_DONE:
563 peer_entry->so = NULL;
564 GNUNET_STATISTICS_update (stats,
565 gettext_noop (
566 "# revocation set unions completed"),
567 1,
568 GNUNET_NO);
569 break;
570 default:
571 GNUNET_break (0);
572 break;
573 }
574}
575
576
577/**
578 * The timeout for performing the set union has expired,
579 * run the set operation on the revocation certificates.
580 *
581 * @param cls NULL
582 */
583static void
584transmit_task_cb (void *cls)
585{
586 struct PeerEntry *peer_entry = cls;
587
588 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
589 "Starting set exchange with peer `%s'\n",
590 GNUNET_i2s (&peer_entry->id));
591 peer_entry->transmit_task = NULL;
592 GNUNET_assert (NULL == peer_entry->so);
593 peer_entry->so = GNUNET_SETU_prepare (&peer_entry->id,
594 &revocation_set_union_app_id,
595 NULL,
596 (struct GNUNET_SETU_Option[]) { { 0 } },
597 &add_revocation,
598 peer_entry);
599 if (GNUNET_OK !=
600 GNUNET_SETU_commit (peer_entry->so,
601 revocation_set))
602 {
603 GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
604 _ ("SET service crashed, terminating revocation service\n"));
605 GNUNET_SCHEDULER_shutdown ();
606 return;
607 }
608}
609
610
611/**
612 * Method called whenever a peer connects. Sets up the PeerEntry and
613 * schedules the initial revocation set exchange with this peer.
614 *
615 * @param cls closure
616 * @param peer peer identity this notification is about
617 */
618static void *
619handle_core_connect (void *cls,
620 const struct GNUNET_PeerIdentity *peer,
621 struct GNUNET_MQ_Handle *mq)
622{
623 struct PeerEntry *peer_entry;
624 struct GNUNET_HashCode my_hash;
625 struct GNUNET_HashCode peer_hash;
626
627 if (0 == GNUNET_memcmp (peer,
628 &my_identity))
629 {
630 return NULL;
631 }
632
633 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
634 "Peer `%s' connected to us\n",
635 GNUNET_i2s (peer));
636 GNUNET_STATISTICS_update (stats,
637 "# peers connected",
638 1,
639 GNUNET_NO);
640 peer_entry = GNUNET_CONTAINER_multipeermap_get (peers,
641 peer);
642 if (NULL != peer_entry)
643 {
644 /* This can happen if "core"'s notification is a tad late
645 and CADET+SET were faster and already produced a
646 #handle_revocation_union_request() for us to deal
647 with. This should be rare, but isn't impossible. */
648 peer_entry->mq = mq;
649 return peer_entry;
650 }
651 peer_entry = new_peer_entry (peer);
652 peer_entry->mq = mq;
653 GNUNET_CRYPTO_hash (&my_identity,
654 sizeof(my_identity),
655 &my_hash);
656 GNUNET_CRYPTO_hash (peer,
657 sizeof(*peer),
658 &peer_hash);
659 if (0 < GNUNET_CRYPTO_hash_cmp (&my_hash,
660 &peer_hash))
661 {
662 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
663 "Starting SET operation with peer `%s'\n",
664 GNUNET_i2s (peer));
665 peer_entry->transmit_task =
666 GNUNET_SCHEDULER_add_delayed (GNUNET_TIME_UNIT_SECONDS,
667 &transmit_task_cb,
668 peer_entry);
669 }
670 return peer_entry;
671}
672
673
674/**
675 * Method called whenever a peer disconnects. Deletes the PeerEntry and cancels
676 * any pending transmission requests to that peer.
677 *
678 * @param cls closure
679 * @param peer peer identity this notification is about
680 * @param internal_cls our `struct PeerEntry` for this peer
681 */
682static void
683handle_core_disconnect (void *cls,
684 const struct GNUNET_PeerIdentity *peer,
685 void *internal_cls)
686{
687 struct PeerEntry *peer_entry = internal_cls;
688
689 if (0 == GNUNET_memcmp (peer,
690 &my_identity))
691 return;
692 GNUNET_assert (NULL != peer_entry);
693 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
694 "Peer `%s' disconnected from us\n",
695 GNUNET_i2s (peer));
696 GNUNET_assert (GNUNET_YES ==
697 GNUNET_CONTAINER_multipeermap_remove (peers,
698 peer,
699 peer_entry));
700 if (NULL != peer_entry->transmit_task)
701 {
702 GNUNET_SCHEDULER_cancel (peer_entry->transmit_task);
703 peer_entry->transmit_task = NULL;
704 }
705 if (NULL != peer_entry->so)
706 {
707 GNUNET_SETU_operation_cancel (peer_entry->so);
708 peer_entry->so = NULL;
709 }
710 GNUNET_free (peer_entry);
711 GNUNET_STATISTICS_update (stats,
712 "# peers connected",
713 -1,
714 GNUNET_NO);
715}
716
717
718/**
719 * Free all values in a hash map.
720 *
721 * @param cls NULL
722 * @param key the key
723 * @param value value to free
724 * @return #GNUNET_OK (continue to iterate)
725 */
726static int
727free_entry (void *cls,
728 const struct GNUNET_HashCode *key,
729 void *value)
730{
731 GNUNET_free (value);
732 return GNUNET_OK;
733}
734
735
736/**
737 * Task run during shutdown.
738 *
739 * @param cls unused
740 */
741static void
742shutdown_task (void *cls)
743{
744 if (NULL != revocation_set)
745 {
746 GNUNET_SETU_destroy (revocation_set);
747 revocation_set = NULL;
748 }
749 if (NULL != revocation_union_listen_handle)
750 {
751 GNUNET_SETU_listen_cancel (revocation_union_listen_handle);
752 revocation_union_listen_handle = NULL;
753 }
754 if (NULL != core_api)
755 {
756 GNUNET_CORE_disconnect (core_api);
757 core_api = NULL;
758 }
759 if (NULL != stats)
760 {
761 GNUNET_STATISTICS_destroy (stats, GNUNET_NO);
762 stats = NULL;
763 }
764 if (NULL != peers)
765 {
766 GNUNET_CONTAINER_multipeermap_destroy (peers);
767 peers = NULL;
768 }
769 if (NULL != revocation_db)
770 {
771 GNUNET_DISK_file_close (revocation_db);
772 revocation_db = NULL;
773 }
774 GNUNET_CONTAINER_multihashmap_iterate (revocation_map,
775 &free_entry,
776 NULL);
777 GNUNET_CONTAINER_multihashmap_destroy (revocation_map);
778}
779
780
781/**
782 * Called on core init/fail.
783 *
784 * @param cls service closure
785 * @param identity the public identity of this peer
786 */
787static void
788core_init (void *cls,
789 const struct GNUNET_PeerIdentity *identity)
790{
791 if (NULL == identity)
792 {
793 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
794 "Connection to core FAILED!\n");
795 GNUNET_SCHEDULER_shutdown ();
796 return;
797 }
798 my_identity = *identity;
799}
800
801
802/**
803 * Called when another peer wants to do a set operation with the
804 * local peer. If a listen error occurs, the 'request' is NULL.
805 *
806 * @param cls closure
807 * @param other_peer the other peer
808 * @param context_msg message with application specific information from
809 * the other peer
810 * @param request request from the other peer (never NULL), use GNUNET_SETU_accept()
811 * to accept it, otherwise the request will be refused
812 * Note that we can't just return value from the listen callback,
813 * as it is also necessary to specify the set we want to do the
814 * operation with, which sometimes can be derived from the context
815 * message. It's necessary to specify the timeout.
816 */
817static void
818handle_revocation_union_request (void *cls,
819 const struct GNUNET_PeerIdentity *other_peer,
820 const struct GNUNET_MessageHeader *context_msg,
821 struct GNUNET_SETU_Request *request)
822{
823 struct PeerEntry *peer_entry;
824
825 if (NULL == request)
826 {
827 GNUNET_break (0);
828 return;
829 }
830 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
831 "Received set exchange request from peer `%s'\n",
832 GNUNET_i2s (other_peer));
833 peer_entry = GNUNET_CONTAINER_multipeermap_get (peers,
834 other_peer);
835 if (NULL == peer_entry)
836 {
837 peer_entry = new_peer_entry (other_peer);
838 }
839 if (NULL != peer_entry->so)
840 {
841 GNUNET_break_op (0);
842 return;
843 }
844 peer_entry->so = GNUNET_SETU_accept (request,
845 (struct GNUNET_SETU_Option[]) { { 0 } },
846 &add_revocation,
847 peer_entry);
848 if (GNUNET_OK !=
849 GNUNET_SETU_commit (peer_entry->so,
850 revocation_set))
851 {
852 GNUNET_break (0);
853 GNUNET_SCHEDULER_shutdown ();
854 return;
855 }
856}
857
858
859/**
860 * Handle network size estimate clients.
861 *
862 * @param cls closure
863 * @param server the initialized server
864 * @param c configuration to use
865 */
866static void
867run (void *cls,
868 const struct GNUNET_CONFIGURATION_Handle *c,
869 struct GNUNET_SERVICE_Handle *service)
870{
871 struct GNUNET_MQ_MessageHandler core_handlers[] = {
872 GNUNET_MQ_hd_var_size (p2p_revoke,
873 GNUNET_MESSAGE_TYPE_REVOCATION_REVOKE,
874 struct RevokeMessage,
875 NULL),
876 GNUNET_MQ_handler_end ()
877 };
878 char *fn;
879 uint64_t left;
880 struct RevokeMessage *rm;
881 struct GNUNET_HashCode hc;
882 const struct GNUNET_CRYPTO_PublicKey *pk;
883
884 GNUNET_CRYPTO_hash ("revocation-set-union-application-id",
885 strlen ("revocation-set-union-application-id"),
886 &revocation_set_union_app_id);
887 if (GNUNET_OK !=
888 GNUNET_CONFIGURATION_get_value_filename (c,
889 "REVOCATION",
890 "DATABASE",
891 &fn))
892 {
893 GNUNET_log_config_missing (GNUNET_ERROR_TYPE_ERROR,
894 "REVOCATION",
895 "DATABASE");
896 GNUNET_SCHEDULER_shutdown ();
897 return;
898 }
899 cfg = c;
900 revocation_map = GNUNET_CONTAINER_multihashmap_create (16,
901 GNUNET_NO);
902 GNUNET_SCHEDULER_add_shutdown (&shutdown_task,
903 NULL);
904 if (GNUNET_OK !=
905 GNUNET_CONFIGURATION_get_value_number (cfg,
906 "REVOCATION",
907 "WORKBITS",
908 &revocation_work_required))
909 {
910 GNUNET_log_config_missing (GNUNET_ERROR_TYPE_ERROR,
911 "REVOCATION",
912 "WORKBITS");
913 GNUNET_SCHEDULER_shutdown ();
914 GNUNET_free (fn);
915 return;
916 }
917 if (revocation_work_required >= sizeof(struct GNUNET_HashCode) * 8)
918 {
919 GNUNET_log_config_invalid (GNUNET_ERROR_TYPE_ERROR,
920 "REVOCATION",
921 "WORKBITS",
922 _ ("Value is too large.\n"));
923 GNUNET_SCHEDULER_shutdown ();
924 GNUNET_free (fn);
925 return;
926 }
927 if (GNUNET_OK !=
928 GNUNET_CONFIGURATION_get_value_time (cfg,
929 "REVOCATION",
930 "EPOCH_DURATION",
931 &epoch_duration))
932 {
933 GNUNET_log_config_missing (GNUNET_ERROR_TYPE_ERROR,
934 "REVOCATION",
935 "EPOCH_DURATION");
936 GNUNET_SCHEDULER_shutdown ();
937 GNUNET_free (fn);
938 return;
939 }
940
941 revocation_set = GNUNET_SETU_create (cfg);
942 revocation_union_listen_handle
943 = GNUNET_SETU_listen (cfg,
944 &revocation_set_union_app_id,
945 &handle_revocation_union_request,
946 NULL);
947 revocation_db = GNUNET_DISK_file_open (fn,
948 GNUNET_DISK_OPEN_READWRITE
949 | GNUNET_DISK_OPEN_CREATE,
950 GNUNET_DISK_PERM_USER_READ
951 | GNUNET_DISK_PERM_USER_WRITE
952 | GNUNET_DISK_PERM_GROUP_READ
953 | GNUNET_DISK_PERM_OTHER_READ);
954 if (NULL == revocation_db)
955 {
956 GNUNET_log_config_invalid (GNUNET_ERROR_TYPE_ERROR,
957 "REVOCATION",
958 "DATABASE",
959 _ ("Could not open revocation database file!"));
960 GNUNET_SCHEDULER_shutdown ();
961 GNUNET_free (fn);
962 return;
963 }
964 if (GNUNET_OK !=
965 GNUNET_DISK_file_size (fn, &left, GNUNET_YES, GNUNET_YES))
966 left = 0;
967 while (left > sizeof(struct RevokeMessage))
968 {
969 rm = GNUNET_new (struct RevokeMessage);
970 if (sizeof(struct RevokeMessage) !=
971 GNUNET_DISK_file_read (revocation_db,
972 rm,
973 sizeof(struct RevokeMessage)))
974 {
975 GNUNET_log_strerror_file (GNUNET_ERROR_TYPE_ERROR,
976 "read",
977 fn);
978 GNUNET_free (rm);
979 GNUNET_SCHEDULER_shutdown ();
980 GNUNET_free (fn);
981 return;
982 }
983 struct GNUNET_REVOCATION_PowP *pow = (struct
984 GNUNET_REVOCATION_PowP *) &rm[1];
985 ssize_t ksize;
986 pk = (const struct GNUNET_CRYPTO_PublicKey *) &pow[1];
987 ksize = GNUNET_CRYPTO_public_key_get_length (pk);
988 if (0 > ksize)
989 {
990 GNUNET_break_op (0);
991 GNUNET_free (rm);
992 GNUNET_free (fn);
993 return;
994 }
995 GNUNET_CRYPTO_hash (pk,
996 ksize,
997 &hc);
998 GNUNET_break (GNUNET_OK ==
999 GNUNET_CONTAINER_multihashmap_put (revocation_map,
1000 &hc,
1001 rm,
1002 GNUNET_CONTAINER_MULTIHASHMAPOPTION_UNIQUE_ONLY));
1003 }
1004 GNUNET_free (fn);
1005
1006 peers = GNUNET_CONTAINER_multipeermap_create (128,
1007 GNUNET_YES);
1008 /* Connect to core service and register core handlers */
1009 core_api = GNUNET_CORE_connect (cfg, /* Main configuration */
1010 NULL, /* Closure passed to functions */
1011 &core_init, /* Call core_init once connected */
1012 &handle_core_connect, /* Handle connects */
1013 &handle_core_disconnect, /* Handle disconnects */
1014 core_handlers); /* Register these handlers */
1015 if (NULL == core_api)
1016 {
1017 GNUNET_SCHEDULER_shutdown ();
1018 return;
1019 }
1020 stats = GNUNET_STATISTICS_create ("revocation",
1021 cfg);
1022}
1023
1024
1025/**
1026 * Define "main" method using service macro.
1027 */
1028GNUNET_SERVICE_MAIN
1029 ("revocation",
1030 GNUNET_SERVICE_OPTION_NONE,
1031 &run,
1032 &client_connect_cb,
1033 &client_disconnect_cb,
1034 NULL,
1035 GNUNET_MQ_hd_var_size (query_message,
1036 GNUNET_MESSAGE_TYPE_REVOCATION_QUERY,
1037 struct QueryMessage,
1038 NULL),
1039 GNUNET_MQ_hd_var_size (revoke_message,
1040 GNUNET_MESSAGE_TYPE_REVOCATION_REVOKE,
1041 struct RevokeMessage,
1042 NULL),
1043 GNUNET_MQ_handler_end ());
1044
1045
1046#if defined(__linux__) && defined(__GLIBC__)
1047#include <malloc.h>
1048
1049/**
1050 * MINIMIZE heap size (way below 128k) since this process doesn't need much.
1051 */
1052void __attribute__ ((constructor))
1053GNUNET_REVOCATION_memory_init ()
1054{
1055 mallopt (M_TRIM_THRESHOLD, 4 * 1024);
1056 mallopt (M_TOP_PAD, 1 * 1024);
1057 malloc_trim (0);
1058}
1059
1060
1061#endif
1062
1063
1064/* 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..9a526af36
--- /dev/null
+++ b/src/service/revocation/meson.build
@@ -0,0 +1,63 @@
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
16 subdir_done()
17endif
18
19libgnunetrevocation = library('gnunetrevocation',
20 libgnunetrevocation_src,
21 soversion: '0',
22 version: '0.0.0',
23 dependencies: [libgnunetutil_dep, libgnunetidentity_dep],
24 include_directories: [incdir, configuration_inc],
25 install: true,
26 install_dir: get_option('libdir'))
27libgnunetrevocation_dep = declare_dependency(link_with : libgnunetrevocation)
28pkg.generate(libgnunetrevocation, url: 'https://www.gnunet.org',
29 description : 'Provides API to perform key revocation in GNUnet')
30
31shared_module('gnunet_plugin_block_revocation',
32 ['plugin_block_revocation.c'],
33 dependencies: [libgnunetutil_dep,
34 libgnunetidentity_dep,
35 libgnunetrevocation_dep,
36 libgnunetblock_dep],
37 include_directories: [incdir, configuration_inc],
38 install: true,
39 install_dir: get_option('libdir')/'gnunet')
40
41executable ('gnunet-revocation',
42 ['gnunet-revocation.c'],
43 dependencies: [libgnunetrevocation_dep,
44 libgnunetutil_dep,
45 libgnunetstatistics_dep,
46 libgnunetcore_dep,
47 libgnunetsetu_dep,
48 libgnunetidentity_dep],
49 include_directories: [incdir, configuration_inc],
50 install: true,
51 install_dir: get_option('bindir'))
52executable ('gnunet-service-revocation',
53 gnunetservicerevocation_src,
54 dependencies: [libgnunetrevocation_dep,
55 libgnunetutil_dep,
56 libgnunetstatistics_dep,
57 libgnunetcore_dep,
58 libgnunetsetu_dep,
59 libgnunetidentity_dep],
60 include_directories: [incdir, configuration_inc],
61 install: true,
62 install_dir: get_option('libdir')/'gnunet'/'libexec')
63
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..90b8c7da0
--- /dev/null
+++ b/src/service/revocation/revocation.h
@@ -0,0 +1,124 @@
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/**
116 * Create the revocation metadata to sign for a revocation message
117 *
118 * @param pow the PoW to sign
119 * @return the signature purpose
120 */
121struct GNUNET_REVOCATION_SignaturePurposePS *
122REV_create_signature_message (const struct GNUNET_REVOCATION_PowP *pow);
123
124#endif
diff --git a/src/service/revocation/revocation_api.c b/src/service/revocation/revocation_api.c
new file mode 100644
index 000000000..3b7d83710
--- /dev/null
+++ b/src/service/revocation/revocation_api.c
@@ -0,0 +1,764 @@
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 * Helper struct that holds a found pow nonce
56 * and the corresponding number of leading zeros.
57 */
58struct BestPow
59{
60 /**
61 * PoW nonce
62 */
63 uint64_t pow;
64
65 /**
66 * Corresponding zero bits in hash
67 */
68 unsigned int bits;
69};
70
71
72/**
73 * The handle to a PoW calculation.
74 * Used in iterative PoW rounds.
75 */
76struct GNUNET_REVOCATION_PowCalculationHandle
77{
78 /**
79 * Current set of found PoWs
80 */
81 struct BestPow best[POW_COUNT];
82
83 /**
84 * The final PoW result data structure.
85 */
86 struct GNUNET_REVOCATION_PowP *pow;
87
88 /**
89 * The current nonce to try
90 */
91 uint64_t current_pow;
92
93 /**
94 * Epochs how long the PoW should be valid.
95 * This is added on top of the difficulty in the PoW.
96 */
97 unsigned int epochs;
98
99 /**
100 * The difficulty (leading zeros) to achieve.
101 */
102 unsigned int difficulty;
103
104};
105
106static struct GNUNET_CRYPTO_PowSalt salt = { "GnsRevocationPow" };
107
108/**
109 * Generic error handler, called with the appropriate
110 * error code and the same closure specified at the creation of
111 * the message queue.
112 * Not every message queue implementation supports an error handler.
113 *
114 * @param cls closure with the `struct GNUNET_NSE_Handle *`
115 * @param error error code
116 */
117static void
118query_mq_error_handler (void *cls,
119 enum GNUNET_MQ_Error error)
120{
121 struct GNUNET_REVOCATION_Query *q = cls;
122
123 GNUNET_log (GNUNET_ERROR_TYPE_INFO,
124 "Revocation query MQ error\n");
125 q->func (q->func_cls,
126 GNUNET_SYSERR);
127 GNUNET_REVOCATION_query_cancel (q);
128}
129
130
131/**
132 * Handle response to our revocation query.
133 *
134 * @param cls our `struct GNUNET_REVOCATION_Query` handle
135 * @param qrm response we got
136 */
137static void
138handle_revocation_query_response (void *cls,
139 const struct QueryResponseMessage *qrm)
140{
141 struct GNUNET_REVOCATION_Query *q = cls;
142
143 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
144 "Revocation query result: %d\n",
145 (uint32_t) ntohl (qrm->is_valid));
146 q->func (q->func_cls,
147 ntohl (qrm->is_valid));
148 GNUNET_REVOCATION_query_cancel (q);
149}
150
151
152/**
153 * Check if a key was revoked.
154 *
155 * @param cfg the configuration to use
156 * @param key key to check for revocation
157 * @param func function to call with the result of the check
158 * @param func_cls closure to pass to @a func
159 * @return handle to use in #GNUNET_REVOCATION_query_cancel to stop REVOCATION from invoking the callback
160 */
161struct GNUNET_REVOCATION_Query *
162GNUNET_REVOCATION_query (const struct GNUNET_CONFIGURATION_Handle *cfg,
163 const struct GNUNET_CRYPTO_PublicKey *key,
164 GNUNET_REVOCATION_Callback func,
165 void *func_cls)
166{
167 struct GNUNET_REVOCATION_Query *q
168 = GNUNET_new (struct GNUNET_REVOCATION_Query);
169 struct GNUNET_MQ_MessageHandler handlers[] = {
170 GNUNET_MQ_hd_fixed_size (revocation_query_response,
171 GNUNET_MESSAGE_TYPE_REVOCATION_QUERY_RESPONSE,
172 struct QueryResponseMessage,
173 q),
174 GNUNET_MQ_handler_end ()
175 };
176 struct QueryMessage *qm;
177 struct GNUNET_MQ_Envelope *env;
178 size_t key_len;
179
180 q->mq = GNUNET_CLIENT_connect (cfg,
181 "revocation",
182 handlers,
183 &query_mq_error_handler,
184 q);
185 if (NULL == q->mq)
186 {
187 GNUNET_free (q);
188 return NULL;
189 }
190 q->func = func;
191 q->func_cls = func_cls;
192 key_len = GNUNET_CRYPTO_public_key_get_length (key);
193 env = GNUNET_MQ_msg_extra (qm, key_len,
194 GNUNET_MESSAGE_TYPE_REVOCATION_QUERY);
195 GNUNET_CRYPTO_write_public_key_to_buffer (key, &qm[1], key_len);
196 qm->key_len = htonl (key_len);
197 GNUNET_MQ_send (q->mq,
198 env);
199 return q;
200}
201
202
203/**
204 * Cancel key revocation check.
205 *
206 * @param q query to cancel
207 */
208void
209GNUNET_REVOCATION_query_cancel (struct GNUNET_REVOCATION_Query *q)
210{
211 if (NULL != q->mq)
212 {
213 GNUNET_MQ_destroy (q->mq);
214 q->mq = NULL;
215 }
216 GNUNET_free (q);
217}
218
219
220/**
221 * Handle for the key revocation operation.
222 */
223struct GNUNET_REVOCATION_Handle
224{
225 /**
226 * Message queue to the service.
227 */
228 struct GNUNET_MQ_Handle *mq;
229
230 /**
231 * Function to call once we are done.
232 */
233 GNUNET_REVOCATION_Callback func;
234
235 /**
236 * Closure for @e func.
237 */
238 void *func_cls;
239};
240
241
242/**
243 * Generic error handler, called with the appropriate
244 * error code and the same closure specified at the creation of
245 * the message queue.
246 * Not every message queue implementation supports an error handler.
247 *
248 * @param cls closure with the `struct GNUNET_NSE_Handle *`
249 * @param error error code
250 */
251static void
252revocation_mq_error_handler (void *cls,
253 enum GNUNET_MQ_Error error)
254{
255 struct GNUNET_REVOCATION_Handle *h = cls;
256
257 GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
258 "Revocation MQ error\n");
259 h->func (h->func_cls,
260 GNUNET_SYSERR);
261 GNUNET_REVOCATION_revoke_cancel (h);
262}
263
264
265/**
266 * Handle response to our revocation query.
267 *
268 * @param cls our `struct GNUNET_REVOCATION_Handle` handle
269 * @param rrm response we got
270 */
271static void
272handle_revocation_response (void *cls,
273 const struct RevocationResponseMessage *rrm)
274{
275 struct GNUNET_REVOCATION_Handle *h = cls;
276
277 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
278 "Revocation transmission result: %d\n",
279 (uint32_t) ntohl (rrm->is_valid));
280 h->func (h->func_cls,
281 ntohl (rrm->is_valid));
282 GNUNET_REVOCATION_revoke_cancel (h);
283}
284
285
286/**
287 * Perform key revocation.
288 *
289 * @param cfg the configuration to use
290 * @param key public key of the key to revoke
291 * @param sig signature to use on the revocation (should have been
292 * created using #GNUNET_REVOCATION_sign_revocation).
293 * @param ts revocation timestamp
294 * @param pow proof of work to use (should have been created by
295 * iteratively calling #GNUNET_REVOCATION_check_pow)
296 * @param func function to call with the result of the check
297 * (called with `is_valid` being #GNUNET_NO if
298 * the revocation worked).
299 * @param func_cls closure to pass to @a func
300 * @return handle to use in #GNUNET_REVOCATION_revoke_cancel to stop REVOCATION from invoking the callback
301 */
302struct GNUNET_REVOCATION_Handle *
303GNUNET_REVOCATION_revoke (const struct GNUNET_CONFIGURATION_Handle *cfg,
304 const struct GNUNET_REVOCATION_PowP *pow,
305 GNUNET_REVOCATION_Callback func,
306 void *func_cls)
307{
308 struct GNUNET_REVOCATION_Handle *h
309 = GNUNET_new (struct GNUNET_REVOCATION_Handle);
310 struct GNUNET_MQ_MessageHandler handlers[] = {
311 GNUNET_MQ_hd_fixed_size (revocation_response,
312 GNUNET_MESSAGE_TYPE_REVOCATION_REVOKE_RESPONSE,
313 struct RevocationResponseMessage,
314 h),
315 GNUNET_MQ_handler_end ()
316 };
317 unsigned long long matching_bits;
318 struct GNUNET_TIME_Relative epoch_duration;
319 struct RevokeMessage *rm;
320 struct GNUNET_MQ_Envelope *env;
321
322 if ((GNUNET_OK !=
323 GNUNET_CONFIGURATION_get_value_number (cfg,
324 "REVOCATION",
325 "WORKBITS",
326 &matching_bits)))
327 {
328 GNUNET_break (0);
329 GNUNET_free (h);
330 return NULL;
331 }
332 if ((GNUNET_OK !=
333 GNUNET_CONFIGURATION_get_value_time (cfg,
334 "REVOCATION",
335 "EPOCH_DURATION",
336 &epoch_duration)))
337 {
338 GNUNET_break (0);
339 GNUNET_free (h);
340 return NULL;
341 }
342 if (GNUNET_YES != GNUNET_REVOCATION_check_pow (pow,
343 (unsigned int) matching_bits,
344 epoch_duration))
345 {
346 GNUNET_break (0);
347 GNUNET_free (h);
348 return NULL;
349 }
350
351
352 h->mq = GNUNET_CLIENT_connect (cfg,
353 "revocation",
354 handlers,
355 &revocation_mq_error_handler,
356 h);
357 if (NULL == h->mq)
358 {
359 GNUNET_free (h);
360 return NULL;
361 }
362 h->func = func;
363 h->func_cls = func_cls;
364 size_t extra_len = GNUNET_REVOCATION_proof_get_size (pow);
365 env = GNUNET_MQ_msg_extra (rm,
366 extra_len,
367 GNUNET_MESSAGE_TYPE_REVOCATION_REVOKE);
368 rm->pow_size = htonl (extra_len);
369 memcpy (&rm[1], pow, extra_len);
370 GNUNET_MQ_send (h->mq,
371 env);
372 return h;
373}
374
375
376void
377GNUNET_REVOCATION_revoke_cancel (struct GNUNET_REVOCATION_Handle *h)
378{
379 if (NULL != h->mq)
380 {
381 GNUNET_MQ_destroy (h->mq);
382 h->mq = NULL;
383 }
384 GNUNET_free (h);
385}
386
387
388/**
389 * Calculate the average zeros in the pows.
390 *
391 * @param ph the PowHandle
392 * @return the average number of zeros.
393 */
394static unsigned int
395calculate_score (const struct GNUNET_REVOCATION_PowCalculationHandle *ph)
396{
397 double sum = 0.0;
398 for (unsigned int j = 0; j<POW_COUNT; j++)
399 sum += ph->best[j].bits;
400 double avg = sum / POW_COUNT;
401 return avg;
402}
403
404
405struct GNUNET_REVOCATION_SignaturePurposePS *
406REV_create_signature_message (const struct GNUNET_REVOCATION_PowP *pow)
407{
408 struct GNUNET_REVOCATION_SignaturePurposePS *spurp;
409 const struct GNUNET_CRYPTO_PublicKey *pk;
410 size_t ksize;
411
412 pk = (const struct GNUNET_CRYPTO_PublicKey *) &pow[1];
413 ksize = GNUNET_CRYPTO_public_key_get_length (pk);
414 spurp = GNUNET_malloc (sizeof (*spurp) + ksize);
415 spurp->timestamp = pow->timestamp;
416 spurp->purpose.purpose = htonl (GNUNET_SIGNATURE_PURPOSE_GNS_REVOCATION);
417 spurp->purpose.size = htonl (sizeof(*spurp) + ksize);
418 GNUNET_CRYPTO_write_public_key_to_buffer (pk,
419 (char*) &spurp[1],
420 ksize);
421 return spurp;
422}
423
424
425enum GNUNET_GenericReturnValue
426check_signature_identity (const struct GNUNET_REVOCATION_PowP *pow,
427 const struct GNUNET_CRYPTO_PublicKey *key)
428{
429 struct GNUNET_REVOCATION_SignaturePurposePS *spurp;
430 unsigned char *sig;
431 size_t ksize;
432 int ret;
433
434 ksize = GNUNET_CRYPTO_public_key_get_length (key);
435 spurp = REV_create_signature_message (pow);
436 sig = ((unsigned char*) &pow[1] + ksize);
437 ret =
438 GNUNET_CRYPTO_signature_verify_raw_ (
439 GNUNET_SIGNATURE_PURPOSE_GNS_REVOCATION,
440 &spurp->purpose,
441 sig,
442 key);
443 GNUNET_free (spurp);
444 return ret == GNUNET_OK ? GNUNET_OK : GNUNET_SYSERR;
445}
446
447
448enum GNUNET_GenericReturnValue
449check_signature (const struct GNUNET_REVOCATION_PowP *pow)
450{
451 const struct GNUNET_CRYPTO_PublicKey *pk;
452
453 pk = (const struct GNUNET_CRYPTO_PublicKey *) &pow[1];
454 return check_signature_identity (pow, pk);
455}
456
457
458/**
459 * Check if the given proof-of-work is valid.
460 *
461 * @param pow proof of work
462 * @param difficulty how many bits must match (configuration) LSD0001: D
463 * @param epoch_duration length of single epoch in configuration
464 * @return #GNUNET_YES if the @a pow is acceptable, #GNUNET_NO if not
465 */
466enum GNUNET_GenericReturnValue
467GNUNET_REVOCATION_check_pow (const struct GNUNET_REVOCATION_PowP *pow,
468 unsigned int difficulty,
469 struct GNUNET_TIME_Relative epoch_duration)
470{
471 char buf[sizeof(struct GNUNET_CRYPTO_PublicKey)
472 + sizeof (struct GNUNET_TIME_AbsoluteNBO)
473 + sizeof (uint64_t)] GNUNET_ALIGN;
474 struct GNUNET_HashCode result;
475 struct GNUNET_TIME_Absolute ts;
476 struct GNUNET_TIME_Absolute exp;
477 struct GNUNET_TIME_Relative ttl;
478 struct GNUNET_TIME_Relative buffer;
479 /* LSD0001: D' */
480 unsigned int score = 0;
481 unsigned int tmp_score = 0;
482 unsigned int epochs;
483 uint64_t pow_val;
484 ssize_t pklen;
485 const struct GNUNET_CRYPTO_PublicKey *pk;
486
487 pk = (const struct GNUNET_CRYPTO_PublicKey *) &pow[1];
488
489 /**
490 * Check if signature valid
491 */
492 if (GNUNET_OK != check_signature (pow))
493 {
494 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
495 "Proof of work signature invalid!\n");
496 return GNUNET_SYSERR;
497 }
498
499 /**
500 * First, check if PoW set is strictly monotically increasing
501 */
502 for (unsigned int i = 0; i < POW_COUNT - 1; i++)
503 {
504 if (GNUNET_ntohll (pow->pow[i]) >= GNUNET_ntohll (pow->pow[i + 1]))
505 return GNUNET_NO;
506 }
507 GNUNET_memcpy (&buf[sizeof(uint64_t)],
508 &pow->timestamp,
509 sizeof (uint64_t));
510 pklen = GNUNET_CRYPTO_public_key_get_length (pk);
511 if (0 > pklen)
512 {
513 GNUNET_break (0);
514 return GNUNET_NO;
515 }
516 GNUNET_memcpy (&buf[sizeof(uint64_t) * 2],
517 pk,
518 pklen);
519 for (unsigned int i = 0; i < POW_COUNT; i++)
520 {
521 pow_val = GNUNET_ntohll (pow->pow[i]);
522 GNUNET_memcpy (buf, &pow->pow[i], sizeof(uint64_t));
523 GNUNET_CRYPTO_pow_hash (&salt,
524 buf,
525 sizeof(buf),
526 &result);
527 tmp_score = GNUNET_CRYPTO_hash_count_leading_zeros (&result);
528 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
529 "Score %u with %" PRIu64 " (#%u)\n",
530 tmp_score, pow_val, i);
531
532 score += tmp_score;
533
534 }
535 score = score / POW_COUNT;
536 if (score < difficulty)
537 return GNUNET_NO;
538 /* LSD0001: (D'-D+1) */
539 epochs = score - difficulty + 1;
540
541 /**
542 * Check expiration
543 */
544 ts = GNUNET_TIME_absolute_ntoh (pow->timestamp);
545 ttl = GNUNET_TIME_relative_multiply (epoch_duration,
546 epochs);
547 /**
548 * Extend by 10% for unsynchronized clocks
549 */
550 buffer = GNUNET_TIME_relative_divide (epoch_duration,
551 10);
552 exp = GNUNET_TIME_absolute_add (ts, ttl);
553 exp = GNUNET_TIME_absolute_add (exp,
554 buffer);
555
556 if (0 != GNUNET_TIME_absolute_get_remaining (ts).rel_value_us)
557 return GNUNET_NO; /* Not yet valid. */
558 /* Revert to actual start time */
559 ts = GNUNET_TIME_absolute_add (ts,
560 buffer);
561
562 if (0 == GNUNET_TIME_absolute_get_remaining (exp).rel_value_us)
563 return GNUNET_NO; /* expired */
564 return GNUNET_YES;
565}
566
567
568enum GNUNET_GenericReturnValue
569sign_pow_identity (const struct GNUNET_CRYPTO_PrivateKey *key,
570 struct GNUNET_REVOCATION_PowP *pow)
571{
572 struct GNUNET_TIME_Absolute ts = GNUNET_TIME_absolute_get ();
573 struct GNUNET_REVOCATION_SignaturePurposePS *rp;
574 const struct GNUNET_CRYPTO_PublicKey *pk;
575 size_t ksize;
576 char *sig;
577
578 /**
579 * Predate the validity period to prevent rejections due to
580 * unsynchronized clocks
581 */
582 ts = GNUNET_TIME_absolute_subtract (ts,
583 GNUNET_TIME_UNIT_WEEKS);
584 pk = (const struct GNUNET_CRYPTO_PublicKey *) &pow[1];
585 ksize = GNUNET_CRYPTO_public_key_get_length (pk);
586 pow->timestamp = GNUNET_TIME_absolute_hton (ts);
587 rp = REV_create_signature_message (pow);
588 sig = ((char*) &pow[1]) + ksize;
589 int result = GNUNET_CRYPTO_sign_raw_ (key,
590 &rp->purpose,
591 (void*) sig);
592 GNUNET_free (rp);
593 if (result == GNUNET_SYSERR)
594 return GNUNET_NO;
595 else
596 return result;
597}
598
599
600enum GNUNET_GenericReturnValue
601sign_pow (const struct GNUNET_CRYPTO_PrivateKey *key,
602 struct GNUNET_REVOCATION_PowP *pow)
603{
604 struct GNUNET_CRYPTO_PublicKey *pk;
605
606 pk = (struct GNUNET_CRYPTO_PublicKey *) &pow[1];
607 GNUNET_CRYPTO_key_get_public (key, pk);
608 return sign_pow_identity (key, pow);
609}
610
611
612/**
613 * Initializes a fresh PoW computation.
614 *
615 * @param key the key to calculate the PoW for.
616 * @param[out] pow starting point for PoW calculation (not yet valid)
617 */
618void
619GNUNET_REVOCATION_pow_init (const struct GNUNET_CRYPTO_PrivateKey *key,
620 struct GNUNET_REVOCATION_PowP *pow)
621{
622 GNUNET_assert (GNUNET_OK == sign_pow (key, pow));
623}
624
625
626struct GNUNET_REVOCATION_PowCalculationHandle*
627GNUNET_REVOCATION_pow_start (struct GNUNET_REVOCATION_PowP *pow,
628 int epochs,
629 unsigned int difficulty)
630{
631 struct GNUNET_REVOCATION_PowCalculationHandle *pc;
632 struct GNUNET_TIME_Relative ttl;
633
634
635 pc = GNUNET_new (struct GNUNET_REVOCATION_PowCalculationHandle);
636 pc->pow = pow;
637 ttl = GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_YEARS,
638 epochs);
639 pc->pow->ttl = GNUNET_TIME_relative_hton (ttl);
640 pc->current_pow = GNUNET_CRYPTO_random_u64 (GNUNET_CRYPTO_QUALITY_WEAK,
641 UINT64_MAX);
642 pc->difficulty = difficulty;
643 pc->epochs = epochs;
644 return pc;
645}
646
647
648/**
649 * Comparison function for quicksort
650 *
651 * @param a left element
652 * @param b right element
653 * @return a-b
654 */
655static int
656cmp_pow_value (const void *a, const void *b)
657{
658 return (GNUNET_ntohll (*(uint64_t*) a) - GNUNET_ntohll (*(uint64_t*) b));
659}
660
661
662/**
663 * Calculate a key revocation valid for broadcasting for a number
664 * of epochs.
665 *
666 * @param pc handle to the PoW, initially called with NULL.
667 * @param epochs number of epochs for which the revocation must be valid.
668 * @param pow current pow value to try
669 * @param difficulty current base difficulty to achieve
670 * @return #GNUNET_YES if the @a pow is acceptable, #GNUNET_NO if not
671 */
672enum GNUNET_GenericReturnValue
673GNUNET_REVOCATION_pow_round (struct GNUNET_REVOCATION_PowCalculationHandle *pc)
674{
675 char buf[sizeof(struct GNUNET_CRYPTO_PublicKey)
676 + sizeof (uint64_t)
677 + sizeof (uint64_t)] GNUNET_ALIGN;
678 struct GNUNET_HashCode result;
679 const struct GNUNET_CRYPTO_PublicKey *pk;
680 unsigned int zeros;
681 int ret;
682 uint64_t pow_nbo;
683 ssize_t ksize;
684
685 pc->current_pow++;
686 pk = (const struct GNUNET_CRYPTO_PublicKey *) &(pc->pow[1]);
687
688 /**
689 * Do not try duplicates
690 */
691 for (unsigned int i = 0; i < POW_COUNT; i++)
692 if (pc->current_pow == pc->best[i].pow)
693 return GNUNET_NO;
694 pow_nbo = GNUNET_htonll (pc->current_pow);
695 GNUNET_memcpy (buf, &pow_nbo, sizeof(uint64_t));
696 GNUNET_memcpy (&buf[sizeof(uint64_t)],
697 &pc->pow->timestamp,
698 sizeof (uint64_t));
699 ksize = GNUNET_CRYPTO_public_key_get_length (pk);
700 GNUNET_assert (0 < ksize);
701 GNUNET_memcpy (&buf[sizeof(uint64_t) * 2],
702 pk,
703 ksize);
704 GNUNET_CRYPTO_pow_hash (&salt,
705 buf,
706 sizeof(buf),
707 &result);
708 zeros = GNUNET_CRYPTO_hash_count_leading_zeros (&result);
709 for (unsigned int i = 0; i < POW_COUNT; i++)
710 {
711 if (pc->best[i].bits < zeros)
712 {
713 pc->best[i].bits = zeros;
714 pc->best[i].pow = pc->current_pow;
715 pc->pow->pow[i] = pow_nbo;
716 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
717 "New best score %u with %" PRIu64 " (#%u)\n",
718 zeros, pc->current_pow, i);
719
720 break;
721 }
722 }
723 ret = calculate_score (pc) >= pc->difficulty + pc->epochs ? GNUNET_YES :
724 GNUNET_NO;
725 if (GNUNET_YES == ret)
726 {
727 /* Sort POWs) */
728 qsort (pc->pow->pow, POW_COUNT, sizeof (uint64_t), &cmp_pow_value);
729 }
730 return ret;
731}
732
733
734/**
735 * Stop a PoW calculation
736 *
737 * @param pc the calculation to clean up
738 * @return #GNUNET_YES if pow valid, #GNUNET_NO if pow was set but is not
739 * valid
740 */
741void
742GNUNET_REVOCATION_pow_stop (struct GNUNET_REVOCATION_PowCalculationHandle *pc)
743{
744 GNUNET_free (pc);
745}
746
747
748size_t
749GNUNET_REVOCATION_proof_get_size (const struct GNUNET_REVOCATION_PowP *pow)
750{
751 size_t size;
752 size_t ksize;
753 const struct GNUNET_CRYPTO_PublicKey *pk;
754
755 size = sizeof (struct GNUNET_REVOCATION_PowP);
756 pk = (const struct GNUNET_CRYPTO_PublicKey *) &pow[1];
757 ksize = GNUNET_CRYPTO_public_key_get_length (pk);
758 size += ksize;
759 size += GNUNET_CRYPTO_signature_get_raw_length_by_type (pk->type);
760 return size;
761}
762
763
764/* 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..66e2cdcc9
--- /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}