diff options
Diffstat (limited to 'src/revocation/revocation_api.c')
-rw-r--r-- | src/revocation/revocation_api.c | 773 |
1 files changed, 0 insertions, 773 deletions
diff --git a/src/revocation/revocation_api.c b/src/revocation/revocation_api.c deleted file mode 100644 index b8c458e4f..000000000 --- a/src/revocation/revocation_api.c +++ /dev/null | |||
@@ -1,773 +0,0 @@ | |||
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 | */ | ||
35 | struct 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 | */ | ||
58 | struct 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 | */ | ||
76 | struct 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 | |||
106 | static 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 | */ | ||
117 | static void | ||
118 | query_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 | */ | ||
137 | static void | ||
138 | handle_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 | */ | ||
161 | struct GNUNET_REVOCATION_Query * | ||
162 | GNUNET_REVOCATION_query (const struct GNUNET_CONFIGURATION_Handle *cfg, | ||
163 | const struct GNUNET_IDENTITY_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 | |||
179 | q->mq = GNUNET_CLIENT_connect (cfg, | ||
180 | "revocation", | ||
181 | handlers, | ||
182 | &query_mq_error_handler, | ||
183 | q); | ||
184 | if (NULL == q->mq) | ||
185 | { | ||
186 | GNUNET_free (q); | ||
187 | return NULL; | ||
188 | } | ||
189 | q->func = func; | ||
190 | q->func_cls = func_cls; | ||
191 | env = GNUNET_MQ_msg (qm, | ||
192 | GNUNET_MESSAGE_TYPE_REVOCATION_QUERY); | ||
193 | qm->reserved = htonl (0); | ||
194 | qm->key = *key; | ||
195 | GNUNET_MQ_send (q->mq, | ||
196 | env); | ||
197 | return q; | ||
198 | } | ||
199 | |||
200 | |||
201 | /** | ||
202 | * Cancel key revocation check. | ||
203 | * | ||
204 | * @param q query to cancel | ||
205 | */ | ||
206 | void | ||
207 | GNUNET_REVOCATION_query_cancel (struct GNUNET_REVOCATION_Query *q) | ||
208 | { | ||
209 | if (NULL != q->mq) | ||
210 | { | ||
211 | GNUNET_MQ_destroy (q->mq); | ||
212 | q->mq = NULL; | ||
213 | } | ||
214 | GNUNET_free (q); | ||
215 | } | ||
216 | |||
217 | |||
218 | /** | ||
219 | * Handle for the key revocation operation. | ||
220 | */ | ||
221 | struct GNUNET_REVOCATION_Handle | ||
222 | { | ||
223 | /** | ||
224 | * Message queue to the service. | ||
225 | */ | ||
226 | struct GNUNET_MQ_Handle *mq; | ||
227 | |||
228 | /** | ||
229 | * Function to call once we are done. | ||
230 | */ | ||
231 | GNUNET_REVOCATION_Callback func; | ||
232 | |||
233 | /** | ||
234 | * Closure for @e func. | ||
235 | */ | ||
236 | void *func_cls; | ||
237 | }; | ||
238 | |||
239 | |||
240 | /** | ||
241 | * Generic error handler, called with the appropriate | ||
242 | * error code and the same closure specified at the creation of | ||
243 | * the message queue. | ||
244 | * Not every message queue implementation supports an error handler. | ||
245 | * | ||
246 | * @param cls closure with the `struct GNUNET_NSE_Handle *` | ||
247 | * @param error error code | ||
248 | */ | ||
249 | static void | ||
250 | revocation_mq_error_handler (void *cls, | ||
251 | enum GNUNET_MQ_Error error) | ||
252 | { | ||
253 | struct GNUNET_REVOCATION_Handle *h = cls; | ||
254 | |||
255 | GNUNET_log (GNUNET_ERROR_TYPE_WARNING, | ||
256 | "Revocation MQ error\n"); | ||
257 | h->func (h->func_cls, | ||
258 | GNUNET_SYSERR); | ||
259 | GNUNET_REVOCATION_revoke_cancel (h); | ||
260 | } | ||
261 | |||
262 | |||
263 | /** | ||
264 | * Handle response to our revocation query. | ||
265 | * | ||
266 | * @param cls our `struct GNUNET_REVOCATION_Handle` handle | ||
267 | * @param rrm response we got | ||
268 | */ | ||
269 | static void | ||
270 | handle_revocation_response (void *cls, | ||
271 | const struct RevocationResponseMessage *rrm) | ||
272 | { | ||
273 | struct GNUNET_REVOCATION_Handle *h = cls; | ||
274 | |||
275 | GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, | ||
276 | "Revocation transmission result: %d\n", | ||
277 | (uint32_t) ntohl (rrm->is_valid)); | ||
278 | h->func (h->func_cls, | ||
279 | ntohl (rrm->is_valid)); | ||
280 | GNUNET_REVOCATION_revoke_cancel (h); | ||
281 | } | ||
282 | |||
283 | |||
284 | /** | ||
285 | * Perform key revocation. | ||
286 | * | ||
287 | * @param cfg the configuration to use | ||
288 | * @param key public key of the key to revoke | ||
289 | * @param sig signature to use on the revocation (should have been | ||
290 | * created using #GNUNET_REVOCATION_sign_revocation). | ||
291 | * @param ts revocation timestamp | ||
292 | * @param pow proof of work to use (should have been created by | ||
293 | * iteratively calling #GNUNET_REVOCATION_check_pow) | ||
294 | * @param func function to call with the result of the check | ||
295 | * (called with `is_valid` being #GNUNET_NO if | ||
296 | * the revocation worked). | ||
297 | * @param func_cls closure to pass to @a func | ||
298 | * @return handle to use in #GNUNET_REVOCATION_revoke_cancel to stop REVOCATION from invoking the callback | ||
299 | */ | ||
300 | struct GNUNET_REVOCATION_Handle * | ||
301 | GNUNET_REVOCATION_revoke (const struct GNUNET_CONFIGURATION_Handle *cfg, | ||
302 | const struct GNUNET_REVOCATION_PowP *pow, | ||
303 | GNUNET_REVOCATION_Callback func, | ||
304 | void *func_cls) | ||
305 | { | ||
306 | struct GNUNET_REVOCATION_Handle *h | ||
307 | = GNUNET_new (struct GNUNET_REVOCATION_Handle); | ||
308 | struct GNUNET_MQ_MessageHandler handlers[] = { | ||
309 | GNUNET_MQ_hd_fixed_size (revocation_response, | ||
310 | GNUNET_MESSAGE_TYPE_REVOCATION_REVOKE_RESPONSE, | ||
311 | struct RevocationResponseMessage, | ||
312 | h), | ||
313 | GNUNET_MQ_handler_end () | ||
314 | }; | ||
315 | unsigned long long matching_bits; | ||
316 | struct GNUNET_TIME_Relative epoch_duration; | ||
317 | struct RevokeMessage *rm; | ||
318 | struct GNUNET_MQ_Envelope *env; | ||
319 | |||
320 | if ((GNUNET_OK != | ||
321 | GNUNET_CONFIGURATION_get_value_number (cfg, | ||
322 | "REVOCATION", | ||
323 | "WORKBITS", | ||
324 | &matching_bits))) | ||
325 | { | ||
326 | GNUNET_break (0); | ||
327 | GNUNET_free (h); | ||
328 | return NULL; | ||
329 | } | ||
330 | if ((GNUNET_OK != | ||
331 | GNUNET_CONFIGURATION_get_value_time (cfg, | ||
332 | "REVOCATION", | ||
333 | "EPOCH_DURATION", | ||
334 | &epoch_duration))) | ||
335 | { | ||
336 | GNUNET_break (0); | ||
337 | GNUNET_free (h); | ||
338 | return NULL; | ||
339 | } | ||
340 | if (GNUNET_YES != GNUNET_REVOCATION_check_pow (pow, | ||
341 | (unsigned int) matching_bits, | ||
342 | epoch_duration)) | ||
343 | { | ||
344 | GNUNET_break (0); | ||
345 | GNUNET_free (h); | ||
346 | return NULL; | ||
347 | } | ||
348 | |||
349 | |||
350 | h->mq = GNUNET_CLIENT_connect (cfg, | ||
351 | "revocation", | ||
352 | handlers, | ||
353 | &revocation_mq_error_handler, | ||
354 | h); | ||
355 | if (NULL == h->mq) | ||
356 | { | ||
357 | GNUNET_free (h); | ||
358 | return NULL; | ||
359 | } | ||
360 | h->func = func; | ||
361 | h->func_cls = func_cls; | ||
362 | size_t extra_len = GNUNET_REVOCATION_proof_get_size (pow); | ||
363 | env = GNUNET_MQ_msg_extra (rm, | ||
364 | extra_len, | ||
365 | GNUNET_MESSAGE_TYPE_REVOCATION_REVOKE); | ||
366 | rm->pow_size = htonl (extra_len); | ||
367 | memcpy (&rm[1], pow, extra_len); | ||
368 | GNUNET_MQ_send (h->mq, | ||
369 | env); | ||
370 | return h; | ||
371 | } | ||
372 | |||
373 | |||
374 | /** | ||
375 | * Cancel key revocation. | ||
376 | * | ||
377 | * @param h operation to cancel | ||
378 | */ | ||
379 | void | ||
380 | GNUNET_REVOCATION_revoke_cancel (struct GNUNET_REVOCATION_Handle *h) | ||
381 | { | ||
382 | if (NULL != h->mq) | ||
383 | { | ||
384 | GNUNET_MQ_destroy (h->mq); | ||
385 | h->mq = NULL; | ||
386 | } | ||
387 | GNUNET_free (h); | ||
388 | } | ||
389 | |||
390 | |||
391 | /** | ||
392 | * Calculate the average zeros in the pows. | ||
393 | * | ||
394 | * @param ph the PowHandle | ||
395 | * @return the average number of zeros. | ||
396 | */ | ||
397 | static unsigned int | ||
398 | calculate_score (const struct GNUNET_REVOCATION_PowCalculationHandle *ph) | ||
399 | { | ||
400 | double sum = 0.0; | ||
401 | for (unsigned int j = 0; j<POW_COUNT; j++) | ||
402 | sum += ph->best[j].bits; | ||
403 | double avg = sum / POW_COUNT; | ||
404 | return avg; | ||
405 | } | ||
406 | |||
407 | struct GNUNET_REVOCATION_SignaturePurposePS * | ||
408 | REV_create_signature_message (const struct GNUNET_REVOCATION_PowP *pow) | ||
409 | { | ||
410 | struct GNUNET_REVOCATION_SignaturePurposePS *spurp; | ||
411 | const struct GNUNET_IDENTITY_PublicKey *pk; | ||
412 | size_t ksize; | ||
413 | |||
414 | pk = (const struct GNUNET_IDENTITY_PublicKey *) &pow[1]; | ||
415 | ksize = GNUNET_IDENTITY_key_get_length (pk); | ||
416 | spurp = GNUNET_malloc (sizeof (*spurp) + ksize); | ||
417 | spurp->timestamp = pow->timestamp; | ||
418 | spurp->purpose.purpose = htonl (GNUNET_SIGNATURE_PURPOSE_REVOCATION); | ||
419 | spurp->purpose.size = htonl (sizeof(*spurp) + ksize); | ||
420 | GNUNET_IDENTITY_write_key_to_buffer (pk, | ||
421 | (char*) &spurp[1], | ||
422 | ksize); | ||
423 | return spurp; | ||
424 | } | ||
425 | |||
426 | enum GNUNET_GenericReturnValue | ||
427 | check_signature_identity (const struct GNUNET_REVOCATION_PowP *pow, | ||
428 | const struct GNUNET_IDENTITY_PublicKey *key) | ||
429 | { | ||
430 | struct GNUNET_REVOCATION_SignaturePurposePS *spurp; | ||
431 | unsigned char *sig; | ||
432 | size_t ksize; | ||
433 | |||
434 | ksize = GNUNET_IDENTITY_key_get_length (key); | ||
435 | spurp = REV_create_signature_message (pow); | ||
436 | sig = ((unsigned char*) &pow[1] + ksize); | ||
437 | if (GNUNET_OK != | ||
438 | GNUNET_IDENTITY_signature_verify_raw_ (GNUNET_SIGNATURE_PURPOSE_REVOCATION, | ||
439 | &spurp->purpose, | ||
440 | sig, | ||
441 | key)) | ||
442 | { | ||
443 | return GNUNET_SYSERR; | ||
444 | } | ||
445 | return GNUNET_OK; | ||
446 | } | ||
447 | |||
448 | |||
449 | enum GNUNET_GenericReturnValue | ||
450 | check_signature (const struct GNUNET_REVOCATION_PowP *pow) | ||
451 | { | ||
452 | const struct GNUNET_IDENTITY_PublicKey *pk; | ||
453 | |||
454 | pk = (const struct GNUNET_IDENTITY_PublicKey *) &pow[1]; | ||
455 | return check_signature_identity (pow, pk); | ||
456 | } | ||
457 | |||
458 | |||
459 | /** | ||
460 | * Check if the given proof-of-work is valid. | ||
461 | * | ||
462 | * @param pow proof of work | ||
463 | * @param difficulty how many bits must match (configuration) LSD0001: D | ||
464 | * @param epoch_duration length of single epoch in configuration | ||
465 | * @return #GNUNET_YES if the @a pow is acceptable, #GNUNET_NO if not | ||
466 | */ | ||
467 | enum GNUNET_GenericReturnValue | ||
468 | GNUNET_REVOCATION_check_pow (const struct GNUNET_REVOCATION_PowP *pow, | ||
469 | unsigned int difficulty, | ||
470 | struct GNUNET_TIME_Relative epoch_duration) | ||
471 | { | ||
472 | char buf[sizeof(struct GNUNET_IDENTITY_PublicKey) | ||
473 | + sizeof (struct GNUNET_TIME_AbsoluteNBO) | ||
474 | + sizeof (uint64_t)] GNUNET_ALIGN; | ||
475 | struct GNUNET_HashCode result; | ||
476 | struct GNUNET_TIME_Absolute ts; | ||
477 | struct GNUNET_TIME_Absolute exp; | ||
478 | struct GNUNET_TIME_Relative ttl; | ||
479 | struct GNUNET_TIME_Relative buffer; | ||
480 | /* LSD0001: D' */ | ||
481 | unsigned int score = 0; | ||
482 | unsigned int tmp_score = 0; | ||
483 | unsigned int epochs; | ||
484 | uint64_t pow_val; | ||
485 | ssize_t pklen; | ||
486 | const struct GNUNET_IDENTITY_PublicKey *pk; | ||
487 | |||
488 | pk = (const struct GNUNET_IDENTITY_PublicKey *) &pow[1]; | ||
489 | |||
490 | /** | ||
491 | * Check if signature valid | ||
492 | */ | ||
493 | if (GNUNET_OK != check_signature (pow)) | ||
494 | { | ||
495 | GNUNET_log (GNUNET_ERROR_TYPE_ERROR, | ||
496 | "Proof of work signature invalid!\n"); | ||
497 | return GNUNET_SYSERR; | ||
498 | } | ||
499 | |||
500 | /** | ||
501 | * First, check if PoW set is strictly monotically increasing | ||
502 | */ | ||
503 | for (unsigned int i = 0; i < POW_COUNT - 1; i++) | ||
504 | { | ||
505 | if (GNUNET_ntohll (pow->pow[i]) >= GNUNET_ntohll (pow->pow[i + 1])) | ||
506 | return GNUNET_NO; | ||
507 | } | ||
508 | GNUNET_memcpy (&buf[sizeof(uint64_t)], | ||
509 | &pow->timestamp, | ||
510 | sizeof (uint64_t)); | ||
511 | pklen = GNUNET_IDENTITY_key_get_length (pk); | ||
512 | if (0 > pklen) | ||
513 | { | ||
514 | GNUNET_break (0); | ||
515 | return GNUNET_NO; | ||
516 | } | ||
517 | GNUNET_memcpy (&buf[sizeof(uint64_t) * 2], | ||
518 | pk, | ||
519 | pklen); | ||
520 | for (unsigned int i = 0; i < POW_COUNT; i++) | ||
521 | { | ||
522 | pow_val = GNUNET_ntohll (pow->pow[i]); | ||
523 | GNUNET_memcpy (buf, &pow->pow[i], sizeof(uint64_t)); | ||
524 | GNUNET_CRYPTO_pow_hash (&salt, | ||
525 | buf, | ||
526 | sizeof(buf), | ||
527 | &result); | ||
528 | tmp_score = GNUNET_CRYPTO_hash_count_leading_zeros (&result); | ||
529 | GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, | ||
530 | "Score %u with %" PRIu64 " (#%u)\n", | ||
531 | tmp_score, pow_val, i); | ||
532 | |||
533 | score += tmp_score; | ||
534 | |||
535 | } | ||
536 | score = score / POW_COUNT; | ||
537 | if (score < difficulty) | ||
538 | return GNUNET_NO; | ||
539 | /* LSD0001: (D'-D+1) */ | ||
540 | epochs = score - difficulty + 1; | ||
541 | |||
542 | /** | ||
543 | * Check expiration | ||
544 | */ | ||
545 | ts = GNUNET_TIME_absolute_ntoh (pow->timestamp); | ||
546 | ttl = GNUNET_TIME_relative_multiply (epoch_duration, | ||
547 | epochs); | ||
548 | /** | ||
549 | * Extend by 10% for unsynchronized clocks | ||
550 | */ | ||
551 | buffer = GNUNET_TIME_relative_divide (epoch_duration, | ||
552 | 10); | ||
553 | exp = GNUNET_TIME_absolute_add (ts, ttl); | ||
554 | exp = GNUNET_TIME_absolute_add (exp, | ||
555 | buffer); | ||
556 | |||
557 | if (0 != GNUNET_TIME_absolute_get_remaining (ts).rel_value_us) | ||
558 | return GNUNET_NO; /* Not yet valid. */ | ||
559 | /* Revert to actual start time */ | ||
560 | ts = GNUNET_TIME_absolute_add (ts, | ||
561 | buffer); | ||
562 | |||
563 | if (0 == GNUNET_TIME_absolute_get_remaining (exp).rel_value_us) | ||
564 | return GNUNET_NO; /* expired */ | ||
565 | return GNUNET_YES; | ||
566 | } | ||
567 | |||
568 | |||
569 | enum GNUNET_GenericReturnValue | ||
570 | sign_pow_identity (const struct GNUNET_IDENTITY_PrivateKey *key, | ||
571 | struct GNUNET_REVOCATION_PowP *pow) | ||
572 | { | ||
573 | struct GNUNET_TIME_Absolute ts = GNUNET_TIME_absolute_get (); | ||
574 | struct GNUNET_REVOCATION_SignaturePurposePS *rp; | ||
575 | const struct GNUNET_IDENTITY_PublicKey *pk; | ||
576 | size_t ksize; | ||
577 | char *sig; | ||
578 | |||
579 | /** | ||
580 | * Predate the validity period to prevent rejections due to | ||
581 | * unsynchronized clocks | ||
582 | */ | ||
583 | ts = GNUNET_TIME_absolute_subtract (ts, | ||
584 | GNUNET_TIME_UNIT_WEEKS); | ||
585 | pk = (const struct GNUNET_IDENTITY_PublicKey *) &pow[1]; | ||
586 | ksize = GNUNET_IDENTITY_key_get_length (pk); | ||
587 | pow->timestamp = GNUNET_TIME_absolute_hton (ts); | ||
588 | rp = REV_create_signature_message (pow); | ||
589 | sig = ((char*) &pow[1]) + ksize; | ||
590 | int result = GNUNET_IDENTITY_sign_raw_ (key, | ||
591 | &rp->purpose, | ||
592 | (void*) sig); | ||
593 | if (result == GNUNET_SYSERR) | ||
594 | return GNUNET_NO; | ||
595 | else | ||
596 | return result; | ||
597 | } | ||
598 | |||
599 | |||
600 | enum GNUNET_GenericReturnValue | ||
601 | sign_pow (const struct GNUNET_IDENTITY_PrivateKey *key, | ||
602 | struct GNUNET_REVOCATION_PowP *pow) | ||
603 | { | ||
604 | struct GNUNET_IDENTITY_PublicKey *pk; | ||
605 | |||
606 | pk = (struct GNUNET_IDENTITY_PublicKey *) &pow[1]; | ||
607 | GNUNET_IDENTITY_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 | */ | ||
618 | void | ||
619 | GNUNET_REVOCATION_pow_init (const struct GNUNET_IDENTITY_PrivateKey *key, | ||
620 | struct GNUNET_REVOCATION_PowP *pow) | ||
621 | { | ||
622 | GNUNET_assert (GNUNET_OK == sign_pow (key, pow)); | ||
623 | } | ||
624 | |||
625 | |||
626 | /** | ||
627 | * Starts a proof-of-work calculation given the pow object as well as | ||
628 | * target epochs and difficulty. | ||
629 | * | ||
630 | * @param pow the PoW to based calculations on. | ||
631 | * @param epochs the number of epochs for which the PoW must be valid. | ||
632 | * @param difficulty the base difficulty of the PoW. | ||
633 | * @return a handle for use in PoW rounds | ||
634 | */ | ||
635 | struct GNUNET_REVOCATION_PowCalculationHandle* | ||
636 | GNUNET_REVOCATION_pow_start (struct GNUNET_REVOCATION_PowP *pow, | ||
637 | int epochs, | ||
638 | unsigned int difficulty) | ||
639 | { | ||
640 | struct GNUNET_REVOCATION_PowCalculationHandle *pc; | ||
641 | struct GNUNET_TIME_Relative ttl; | ||
642 | |||
643 | |||
644 | pc = GNUNET_new (struct GNUNET_REVOCATION_PowCalculationHandle); | ||
645 | pc->pow = pow; | ||
646 | ttl = GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_YEARS, | ||
647 | epochs); | ||
648 | pc->pow->ttl = GNUNET_TIME_relative_hton (ttl); | ||
649 | pc->current_pow = GNUNET_CRYPTO_random_u64 (GNUNET_CRYPTO_QUALITY_WEAK, | ||
650 | UINT64_MAX); | ||
651 | pc->difficulty = difficulty; | ||
652 | pc->epochs = epochs; | ||
653 | return pc; | ||
654 | } | ||
655 | |||
656 | |||
657 | /** | ||
658 | * Comparison function for quicksort | ||
659 | * | ||
660 | * @param a left element | ||
661 | * @param b right element | ||
662 | * @return a-b | ||
663 | */ | ||
664 | static int | ||
665 | cmp_pow_value (const void *a, const void *b) | ||
666 | { | ||
667 | return (GNUNET_ntohll (*(uint64_t*) a) - GNUNET_ntohll (*(uint64_t*) b)); | ||
668 | } | ||
669 | |||
670 | |||
671 | /** | ||
672 | * Calculate a key revocation valid for broadcasting for a number | ||
673 | * of epochs. | ||
674 | * | ||
675 | * @param pc handle to the PoW, initially called with NULL. | ||
676 | * @param epochs number of epochs for which the revocation must be valid. | ||
677 | * @param pow current pow value to try | ||
678 | * @param difficulty current base difficulty to achieve | ||
679 | * @return #GNUNET_YES if the @a pow is acceptable, #GNUNET_NO if not | ||
680 | */ | ||
681 | enum GNUNET_GenericReturnValue | ||
682 | GNUNET_REVOCATION_pow_round (struct GNUNET_REVOCATION_PowCalculationHandle *pc) | ||
683 | { | ||
684 | char buf[sizeof(struct GNUNET_IDENTITY_PublicKey) | ||
685 | + sizeof (uint64_t) | ||
686 | + sizeof (uint64_t)] GNUNET_ALIGN; | ||
687 | struct GNUNET_HashCode result; | ||
688 | const struct GNUNET_IDENTITY_PublicKey *pk; | ||
689 | unsigned int zeros; | ||
690 | int ret; | ||
691 | uint64_t pow_nbo; | ||
692 | ssize_t ksize; | ||
693 | |||
694 | pc->current_pow++; | ||
695 | pk = (const struct GNUNET_IDENTITY_PublicKey *) &(pc->pow[1]); | ||
696 | |||
697 | /** | ||
698 | * Do not try duplicates | ||
699 | */ | ||
700 | for (unsigned int i = 0; i < POW_COUNT; i++) | ||
701 | if (pc->current_pow == pc->best[i].pow) | ||
702 | return GNUNET_NO; | ||
703 | pow_nbo = GNUNET_htonll (pc->current_pow); | ||
704 | GNUNET_memcpy (buf, &pow_nbo, sizeof(uint64_t)); | ||
705 | GNUNET_memcpy (&buf[sizeof(uint64_t)], | ||
706 | &pc->pow->timestamp, | ||
707 | sizeof (uint64_t)); | ||
708 | ksize = GNUNET_IDENTITY_key_get_length (pk); | ||
709 | GNUNET_assert (0 < ksize); | ||
710 | GNUNET_memcpy (&buf[sizeof(uint64_t) * 2], | ||
711 | pk, | ||
712 | ksize); | ||
713 | GNUNET_CRYPTO_pow_hash (&salt, | ||
714 | buf, | ||
715 | sizeof(buf), | ||
716 | &result); | ||
717 | zeros = GNUNET_CRYPTO_hash_count_leading_zeros (&result); | ||
718 | for (unsigned int i = 0; i < POW_COUNT; i++) | ||
719 | { | ||
720 | if (pc->best[i].bits < zeros) | ||
721 | { | ||
722 | pc->best[i].bits = zeros; | ||
723 | pc->best[i].pow = pc->current_pow; | ||
724 | pc->pow->pow[i] = pow_nbo; | ||
725 | GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, | ||
726 | "New best score %u with %" PRIu64 " (#%u)\n", | ||
727 | zeros, pc->current_pow, i); | ||
728 | |||
729 | break; | ||
730 | } | ||
731 | } | ||
732 | ret = calculate_score (pc) >= pc->difficulty + pc->epochs ? GNUNET_YES : | ||
733 | GNUNET_NO; | ||
734 | if (GNUNET_YES == ret) | ||
735 | { | ||
736 | /* Sort POWs) */ | ||
737 | qsort (pc->pow->pow, POW_COUNT, sizeof (uint64_t), &cmp_pow_value); | ||
738 | } | ||
739 | return ret; | ||
740 | } | ||
741 | |||
742 | |||
743 | /** | ||
744 | * Stop a PoW calculation | ||
745 | * | ||
746 | * @param pc the calculation to clean up | ||
747 | * @return #GNUNET_YES if pow valid, #GNUNET_NO if pow was set but is not | ||
748 | * valid | ||
749 | */ | ||
750 | void | ||
751 | GNUNET_REVOCATION_pow_stop (struct GNUNET_REVOCATION_PowCalculationHandle *pc) | ||
752 | { | ||
753 | GNUNET_free (pc); | ||
754 | } | ||
755 | |||
756 | |||
757 | size_t | ||
758 | GNUNET_REVOCATION_proof_get_size (const struct GNUNET_REVOCATION_PowP *pow) | ||
759 | { | ||
760 | size_t size; | ||
761 | size_t ksize; | ||
762 | const struct GNUNET_IDENTITY_PublicKey *pk; | ||
763 | |||
764 | size = sizeof (struct GNUNET_REVOCATION_PowP); | ||
765 | pk = (const struct GNUNET_IDENTITY_PublicKey *) &pow[1]; | ||
766 | ksize = GNUNET_IDENTITY_key_get_length (pk); | ||
767 | size += ksize; | ||
768 | size += GNUNET_IDENTITY_signature_get_raw_length_by_type (pk->type); | ||
769 | return size; | ||
770 | } | ||
771 | |||
772 | |||
773 | /* end of revocation_api.c */ | ||