acc13ba67950b3c8f7e3dc92135bf6710c619fc6
[oweals/gnunet.git] / src / revocation / revocation_api.c
1 /*
2       This file is part of GNUnet
3       (C) 2013 Christian Grothoff (and other contributing authors)
4
5       GNUnet is free software; you can redistribute it and/or modify
6       it under the terms of the GNU General Public Licerevocation as published
7       by the Free Software Foundation; either version 3, or (at your
8       option) any later version.
9
10       GNUnet is distributed in the hope that it will be useful, but
11       WITHOUT ANY WARRANTY; without even the implied warranty of
12       MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
13       General Public Licerevocation for more details.
14
15       You should have received a copy of the GNU General Public Licerevocation
16       along with GNUnet; see the file COPYING.  If not, write to the
17       Free Software Foundation, Inc., 59 Temple Place - Suite 330,
18       Boston, MA 02111-1307, USA.
19  */
20 /**
21  * @file 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 <gcrypt.h>
31
32
33 /**
34  * Handle for the key revocation query.
35  */
36 struct GNUNET_REVOCATION_Query
37 {
38
39   /**
40    * Connection to the service.
41    */
42   struct GNUNET_CLIENT_Connection *client;
43
44   /**
45    * Our configuration.
46    */
47   const struct GNUNET_CONFIGURATION_Handle *cfg;
48
49   /**
50    * Key to check.
51    */
52   struct GNUNET_CRYPTO_EccPublicSignKey key;
53
54   /**
55    * Function to call with the result.
56    */
57   GNUNET_REVOCATION_Callback func;
58
59   /**
60    * Closure for @e func.
61    */
62   void *func_cls;
63
64   /**
65    * Transmission handle to the service.
66    */
67   struct GNUNET_CLIENT_TransmitHandle *th;
68
69 };
70
71
72 /**
73  * Handle response to our revocation query.
74  *
75  * @param cls our `struct GNUNET_REVOCATION_Query` handle
76  * @param msg response we got, NULL on disconnect
77  */
78 static void
79 handle_revocation_query_response (void *cls,
80                                   const struct GNUNET_MessageHeader *msg)
81 {
82   struct GNUNET_REVOCATION_Query *q = cls;
83   const struct QueryResponseMessage *qrm;
84
85   if ( (NULL == msg) ||
86        (sizeof (struct QueryResponseMessage) != ntohs (msg->size)) ||
87        (GNUNET_MESSAGE_TYPE_REVOCATION_QUERY_RESPONSE != ntohs (msg->type)) )
88   {
89     GNUNET_break (NULL == msg);
90     q->func (q->func_cls, GNUNET_SYSERR);
91     GNUNET_REVOCATION_query_cancel (q);
92     return;
93   }
94   qrm = (const struct QueryResponseMessage *) msg;
95   q->func (q->func_cls, ntohl (qrm->is_valid));
96   GNUNET_REVOCATION_query_cancel (q);
97 }
98
99
100 /**
101  * Transmit our revocation query to the service.
102  *
103  * @param cls our `struct GNUNET_REVOCATION_Query` handle
104  * @param size number of bytes available in @a buf
105  * @param buf where to copy the query
106  * @return number of bytes copied to @a buf
107  */
108 static size_t
109 send_revocation_query (void *cls,
110                        size_t size,
111                        void *buf)
112 {
113   struct GNUNET_REVOCATION_Query *q = cls;
114   struct QueryMessage qm;
115
116   q->th = NULL;
117   if ( (NULL == buf) ||
118        (sizeof (struct QueryMessage) > size) )
119   {
120     GNUNET_break (0);
121     q->func (q->func_cls, GNUNET_SYSERR);
122     GNUNET_REVOCATION_query_cancel (q);
123     return 0;
124   }
125   qm.header.size = htons (sizeof (struct QueryMessage));
126   qm.header.type = htons (GNUNET_MESSAGE_TYPE_REVOCATION_QUERY);
127   qm.reserved = htonl (0);
128   qm.key = q->key;
129   memcpy (buf, &qm, sizeof (struct QueryMessage));
130   GNUNET_CLIENT_receive (q->client,
131                          &handle_revocation_query_response,
132                          q,
133                          GNUNET_TIME_UNIT_FOREVER_REL);
134   return sizeof (struct QueryMessage);
135 }
136
137
138 /**
139  * Check if a key was revoked.
140  *
141  * @param cfg the configuration to use
142  * @param key key to check for revocation
143  * @param func funtion to call with the result of the check
144  * @param func_cls closure to pass to @a func
145  * @return handle to use in #GNUNET_REVOCATION_query_cancel to stop REVOCATION from invoking the callback
146  */
147 struct GNUNET_REVOCATION_Query *
148 GNUNET_REVOCATION_query (const struct GNUNET_CONFIGURATION_Handle *cfg,
149                          const struct GNUNET_CRYPTO_EccPublicSignKey *key,
150                          GNUNET_REVOCATION_Callback func, void *func_cls)
151 {
152   struct GNUNET_REVOCATION_Query *q;
153
154   q = GNUNET_new (struct GNUNET_REVOCATION_Query);
155   q->client = GNUNET_CLIENT_connect ("revocation", cfg);
156   if (NULL == q->client)
157   {
158     GNUNET_break (0);
159     GNUNET_free (q);
160     return NULL;
161   }
162   q->cfg = cfg;
163   q->key = *key;
164   q->func = func;
165   q->func_cls = func_cls;
166   q->th = GNUNET_CLIENT_notify_transmit_ready (q->client,
167                                                sizeof (struct QueryMessage),
168                                                GNUNET_TIME_UNIT_FOREVER_REL,
169                                                GNUNET_YES,
170                                                &send_revocation_query,
171                                                q);
172   return q;
173 }
174
175
176 /**
177  * Cancel key revocation check.
178  *
179  * @param q query to cancel
180  */
181 void
182 GNUNET_REVOCATION_query_cancel (struct GNUNET_REVOCATION_Query *q)
183 {
184   if (NULL != q->th)
185   {
186     GNUNET_CLIENT_notify_transmit_ready_cancel (q->th);
187     q->th = NULL;
188   }
189   GNUNET_CLIENT_disconnect (q->client);
190   GNUNET_free (q);
191 }
192
193
194 /**
195  * Handle for the key revocation operation.
196  */
197 struct GNUNET_REVOCATION_Handle
198 {
199
200   /**
201    * Connection to the service.
202    */
203   struct GNUNET_CLIENT_Connection *client;
204
205   /**
206    * Our configuration.
207    */
208   const struct GNUNET_CONFIGURATION_Handle *cfg;
209
210   /**
211    * Key to revoke.
212    */
213   struct GNUNET_CRYPTO_EccPublicSignKey key;
214
215   /**
216    * Signature showing that we have the right to revoke.
217    */
218   struct GNUNET_CRYPTO_EccSignature sig;
219
220   /**
221    * Proof of work showing that we spent enough resources to broadcast revocation.
222    */
223   uint64_t pow;
224
225   /**
226    * Function to call once we are done.
227    */
228   GNUNET_REVOCATION_Callback func;
229
230   /**
231    * Closure for @e func.
232    */
233   void *func_cls;
234
235   /**
236    * Transmission handle to the service.
237    */
238   struct GNUNET_CLIENT_TransmitHandle *th;
239
240 };
241
242
243 /**
244  * Handle response to our revocation query.
245  *
246  * @param cls our `struct GNUNET_REVOCATION_Handle` handle
247  * @param msg response we got, NULL on disconnect
248  */
249 static void
250 handle_revocation_response (void *cls,
251                             const struct GNUNET_MessageHeader *msg)
252 {
253   struct GNUNET_REVOCATION_Handle *h = cls;
254   const struct RevocationResponseMessage *rrm;
255
256   if ( (NULL == msg) ||
257        (sizeof (struct RevocationResponseMessage) != ntohs (msg->size)) ||
258        (GNUNET_MESSAGE_TYPE_REVOCATION_REVOKE_RESPONSE != ntohs (msg->type)) )
259   {
260     GNUNET_break (NULL == msg);
261     h->func (h->func_cls, GNUNET_SYSERR);
262     GNUNET_REVOCATION_revoke_cancel (h);
263     return;
264   }
265   rrm = (const struct RevocationResponseMessage *) msg;
266   h->func (h->func_cls, ntohl (rrm->is_valid));
267   GNUNET_REVOCATION_revoke_cancel (h);
268
269 }
270
271
272 /**
273  * Transmit our revocation to the service.
274  *
275  * @param cls our `struct GNUNET_REVOCATION_Handle` handle
276  * @param size number of bytes available in @a buf
277  * @param buf where to copy the query
278  * @return number of bytes copied to @a buf
279  */
280 static size_t
281 send_revoke (void *cls,
282              size_t size,
283              void *buf)
284 {
285   struct GNUNET_REVOCATION_Handle *h = cls;
286   struct RevokeMessage rm;
287
288   h->th = NULL;
289   if ( (NULL == buf) ||
290        (sizeof (struct RevokeMessage) > size) )
291   {
292     GNUNET_break (0);
293     h->func (h->func_cls, GNUNET_SYSERR);
294     GNUNET_REVOCATION_revoke_cancel (h);
295     return 0;
296   }
297   rm.header.size = htons (sizeof (struct QueryMessage));
298   rm.header.type = htons (GNUNET_MESSAGE_TYPE_REVOCATION_QUERY);
299   rm.reserved = htonl (0);
300   rm.proof_of_work = h->pow;
301   rm.purpose.purpose = htonl (GNUNET_SIGNATURE_PURPOSE_REVOCATION);
302   rm.purpose.size = htonl (sizeof (struct GNUNET_CRYPTO_EccSignaturePurpose) +
303                            sizeof (struct GNUNET_CRYPTO_EccPublicSignKey));
304   rm.public_key = h->key;
305   rm.signature = h->sig;
306   memcpy (buf, &rm, sizeof (struct RevokeMessage));
307   GNUNET_CLIENT_receive (h->client,
308                          &handle_revocation_response,
309                          h,
310                          GNUNET_TIME_UNIT_FOREVER_REL);
311   return sizeof (struct RevokeMessage);
312 }
313
314
315 /**
316  * Perform key revocation.
317  *
318  * @param cfg the configuration to use
319  * @param key public key of the key to revoke
320  * @param sig signature to use on the revocation (should have been
321  *            created using #GNUNET_REVOCATION_sign_revocation).
322  * @param pow proof of work to use (should have been created by
323  *            iteratively calling #GNUNET_REVOCATION_check_pow)
324  * @param func funtion to call with the result of the check
325  *             (called with `is_valid` being #GNUNET_NO if
326  *              the revocation worked).
327  * @param func_cls closure to pass to @a func
328  * @return handle to use in #GNUNET_REVOCATION_revoke_cancel to stop REVOCATION from invoking the callback
329  */
330 struct GNUNET_REVOCATION_Handle *
331 GNUNET_REVOCATION_revoke (const struct GNUNET_CONFIGURATION_Handle *cfg,
332                           const struct GNUNET_CRYPTO_EccPublicSignKey *key,
333                           const struct GNUNET_CRYPTO_EccSignature *sig,
334                           uint64_t pow,
335                           GNUNET_REVOCATION_Callback func, void *func_cls)
336 {
337   struct GNUNET_REVOCATION_Handle *h;
338   unsigned long long matching_bits;
339
340   if ( (GNUNET_OK ==
341         GNUNET_CONFIGURATION_get_value_number (cfg,
342                                                "REVOCATION",
343                                                "WORKBITS",
344                                                &matching_bits)) &&
345        (GNUNET_YES !=
346         GNUNET_REVOCATION_check_pow (key, pow,
347                                      (unsigned int) matching_bits)) )
348   {
349     GNUNET_break (0);
350     return NULL;
351   }
352   h = GNUNET_new (struct GNUNET_REVOCATION_Handle);
353   h->client = GNUNET_CLIENT_connect ("revocation", cfg);
354   h->cfg = cfg;
355   h->key = *key;
356   h->sig = *sig;
357   h->pow = pow;
358   h->func = func;
359   h->func_cls = func_cls;
360   h->th = GNUNET_CLIENT_notify_transmit_ready (h->client,
361                                                sizeof (struct RevokeMessage),
362                                                GNUNET_TIME_UNIT_FOREVER_REL,
363                                                GNUNET_YES,
364                                                &send_revoke,
365                                                h);
366   return h;
367 }
368
369
370 /**
371  * Cancel key revocation.
372  *
373  * @param h operation to cancel
374  */
375 void
376 GNUNET_REVOCATION_revoke_cancel (struct GNUNET_REVOCATION_Handle *h)
377 {
378   if (NULL != h->th)
379   {
380     GNUNET_CLIENT_notify_transmit_ready_cancel (h->th);
381     h->th = NULL;
382   }
383   GNUNET_CLIENT_disconnect (h->client);
384   GNUNET_free (h);
385 }
386
387
388
389 /**
390  * Calculate the 'proof-of-work' hash (an expensive hash).
391  *
392  * @param buf data to hash
393  * @param buf_len number of bytes in @a buf
394  * @param result where to write the resulting hash
395  */
396 static void
397 pow_hash (const void *buf,
398           size_t buf_len,
399           struct GNUNET_HashCode *result)
400 {
401   GNUNET_break (0 ==
402                 gcry_kdf_derive (buf, buf_len,
403                                  GCRY_KDF_SCRYPT,
404                                  1 /* subalgo */,
405                                  "gnunet-revocation-proof-of-work",
406                                  strlen ("gnunet-revocation-proof-of-work"),
407                                  2 /* iterations; keep cost of individual op small */,
408                                  sizeof (struct GNUNET_HashCode), result));
409 }
410
411
412 /**
413  * Count the leading zeroes in hash.
414  *
415  * @param hash to count leading zeros in
416  * @return the number of leading zero bits.
417  */
418 static unsigned int
419 count_leading_zeroes (const struct GNUNET_HashCode *hash)
420 {
421   unsigned int hash_count;
422
423   hash_count = 0;
424   while ((0 == GNUNET_CRYPTO_hash_get_bit (hash, hash_count)))
425     hash_count++;
426   return hash_count;
427 }
428
429
430 /**
431  * Check if the given proof-of-work value
432  * would be acceptable for revoking the given key.
433  *
434  * @param key key to check for
435  * @param pow proof of work value
436  * @param matching_bits how many bits must match (configuration)
437  * @return #GNUNET_YES if the @a pow is acceptable, #GNUNET_NO if not
438  */
439 int
440 GNUNET_REVOCATION_check_pow (const struct GNUNET_CRYPTO_EccPublicSignKey *key,
441                              uint64_t pow,
442                              unsigned int matching_bits)
443 {
444   char buf[sizeof (struct GNUNET_CRYPTO_EccPublicSignKey) +
445            sizeof (pow)] GNUNET_ALIGN;
446   struct GNUNET_HashCode result;
447
448   memcpy (buf, &pow, sizeof (pow));
449   memcpy (&buf[sizeof (pow)], key,
450           sizeof (struct GNUNET_CRYPTO_EccPublicSignKey));
451   pow_hash (buf, sizeof (buf), &result);
452   return (count_leading_zeroes (&result) >=
453           matching_bits) ? GNUNET_YES : GNUNET_NO;
454 }
455
456
457 /**
458  * Create a revocation signature.
459  *
460  * @param key private key of the key to revoke
461  * @param sig where to write the revocation signature
462  */
463 void
464 GNUNET_REVOCATION_sign_revocation (const struct GNUNET_CRYPTO_EccPrivateKey *key,
465                                    struct GNUNET_CRYPTO_EccSignature *sig)
466 {
467   struct RevokeMessage rm;
468
469   rm.purpose.purpose = htonl (GNUNET_SIGNATURE_PURPOSE_REVOCATION);
470   rm.purpose.size = htonl (sizeof (struct GNUNET_CRYPTO_EccSignaturePurpose) +
471                            sizeof (struct GNUNET_CRYPTO_EccPublicSignKey));
472   GNUNET_CRYPTO_ecc_key_get_public_for_signature (key, &rm.public_key);
473   GNUNET_assert (GNUNET_OK ==
474                  GNUNET_CRYPTO_ecc_sign (key,
475                                          &rm.purpose,
476                                          sig));
477 }
478
479
480 /* end of revocation_api.c */
481