8c00ac2ae680bbef1d76647fe2291354fde7f25a
[oweals/gnunet.git] / src / revocation / revocation_api.c
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
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., 51 Franklin Street, Fifth Floor,
18       Boston, MA 02110-1301, 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    * Message queue to the service.
41    */
42   struct GNUNET_MQ_Handle *mq;
43
44   /**
45    * Function to call with the result.
46    */
47   GNUNET_REVOCATION_Callback func;
48
49   /**
50    * Closure for @e func.
51    */
52   void *func_cls;
53
54 };
55
56
57 /**
58  * Generic error handler, called with the appropriate
59  * error code and the same closure specified at the creation of
60  * the message queue.
61  * Not every message queue implementation supports an error handler.
62  *
63  * @param cls closure with the `struct GNUNET_NSE_Handle *`
64  * @param error error code
65  */
66 static void
67 query_mq_error_handler (void *cls,
68                         enum GNUNET_MQ_Error error)
69 {
70   struct GNUNET_REVOCATION_Query *q = cls;
71
72   GNUNET_log (GNUNET_ERROR_TYPE_INFO,
73               "Revocation query MQ error\n");
74   q->func (q->func_cls,
75            GNUNET_SYSERR);
76   GNUNET_REVOCATION_query_cancel (q);
77 }
78
79
80 /**
81  * Handle response to our revocation query.
82  *
83  * @param cls our `struct GNUNET_REVOCATION_Query` handle
84  * @param qrm response we got
85  */
86 static void
87 handle_revocation_query_response (void *cls,
88                                   const struct QueryResponseMessage *qrm)
89 {
90   struct GNUNET_REVOCATION_Query *q = cls;
91
92   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
93               "Revocation query result: %d\n",
94               ntohl (qrm->is_valid));
95   q->func (q->func_cls,
96            ntohl (qrm->is_valid));
97   GNUNET_REVOCATION_query_cancel (q);
98 }
99
100
101 /**
102  * Check if a key was revoked.
103  *
104  * @param cfg the configuration to use
105  * @param key key to check for revocation
106  * @param func funtion to call with the result of the check
107  * @param func_cls closure to pass to @a func
108  * @return handle to use in #GNUNET_REVOCATION_query_cancel to stop REVOCATION from invoking the callback
109  */
110 struct GNUNET_REVOCATION_Query *
111 GNUNET_REVOCATION_query (const struct GNUNET_CONFIGURATION_Handle *cfg,
112                          const struct GNUNET_CRYPTO_EcdsaPublicKey *key,
113                          GNUNET_REVOCATION_Callback func,
114                          void *func_cls)
115 {
116   struct GNUNET_REVOCATION_Query *q
117     = GNUNET_new (struct GNUNET_REVOCATION_Query);
118   struct GNUNET_MQ_MessageHandler handlers[] = {
119     GNUNET_MQ_hd_fixed_size (revocation_query_response,
120                              GNUNET_MESSAGE_TYPE_REVOCATION_QUERY_RESPONSE,
121                              struct QueryResponseMessage,
122                              q),
123     GNUNET_MQ_handler_end ()
124   };
125   struct QueryMessage *qm;
126   struct GNUNET_MQ_Envelope *env;
127
128   q->mq = GNUNET_CLIENT_connecT (cfg,
129                                  "revocation",
130                                  handlers,
131                                  &query_mq_error_handler,
132                                  q);
133   if (NULL == q->mq)
134   {
135     GNUNET_free (q);
136     return NULL;
137   }
138   q->func = func;
139   q->func_cls = func_cls;
140   env = GNUNET_MQ_msg (qm,
141                        GNUNET_MESSAGE_TYPE_REVOCATION_QUERY);
142   qm->reserved = htonl (0);
143   qm->key = *key;
144   GNUNET_MQ_send (q->mq,
145                   env);
146   return q;
147 }
148
149
150 /**
151  * Cancel key revocation check.
152  *
153  * @param q query to cancel
154  */
155 void
156 GNUNET_REVOCATION_query_cancel (struct GNUNET_REVOCATION_Query *q)
157 {
158   if (NULL != q->mq)
159   {
160     GNUNET_MQ_destroy (q->mq);
161     q->mq = NULL;
162   }
163   GNUNET_free (q);
164 }
165
166
167 /**
168  * Handle for the key revocation operation.
169  */
170 struct GNUNET_REVOCATION_Handle
171 {
172
173   /**
174    * Message queue to the service.
175    */
176   struct GNUNET_MQ_Handle *mq;
177
178   /**
179    * Function to call once we are done.
180    */
181   GNUNET_REVOCATION_Callback func;
182
183   /**
184    * Closure for @e func.
185    */
186   void *func_cls;
187
188 };
189
190
191 /**
192  * Generic error handler, called with the appropriate
193  * error code and the same closure specified at the creation of
194  * the message queue.
195  * Not every message queue implementation supports an error handler.
196  *
197  * @param cls closure with the `struct GNUNET_NSE_Handle *`
198  * @param error error code
199  */
200 static void
201 revocation_mq_error_handler (void *cls,
202                              enum GNUNET_MQ_Error error)
203 {
204   struct GNUNET_REVOCATION_Handle *h = cls;
205
206   GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
207               "Revocation MQ error\n");
208   h->func (h->func_cls,
209            GNUNET_SYSERR);
210   GNUNET_REVOCATION_revoke_cancel (h);
211 }
212
213
214 /**
215  * Handle response to our revocation query.
216  *
217  * @param cls our `struct GNUNET_REVOCATION_Handle` handle
218  * @param rrm response we got
219  */
220 static void
221 handle_revocation_response (void *cls,
222                             const struct RevocationResponseMessage *rrm)
223 {
224   struct GNUNET_REVOCATION_Handle *h = cls;
225
226   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
227               "Revocation transmission result: %d\n",
228               ntohl (rrm->is_valid));
229   h->func (h->func_cls,
230            ntohl (rrm->is_valid));
231   GNUNET_REVOCATION_revoke_cancel (h);
232 }
233
234
235 /**
236  * Perform key revocation.
237  *
238  * @param cfg the configuration to use
239  * @param key public key of the key to revoke
240  * @param sig signature to use on the revocation (should have been
241  *            created using #GNUNET_REVOCATION_sign_revocation).
242  * @param pow proof of work to use (should have been created by
243  *            iteratively calling #GNUNET_REVOCATION_check_pow)
244  * @param func funtion to call with the result of the check
245  *             (called with `is_valid` being #GNUNET_NO if
246  *              the revocation worked).
247  * @param func_cls closure to pass to @a func
248  * @return handle to use in #GNUNET_REVOCATION_revoke_cancel to stop REVOCATION from invoking the callback
249  */
250 struct GNUNET_REVOCATION_Handle *
251 GNUNET_REVOCATION_revoke (const struct GNUNET_CONFIGURATION_Handle *cfg,
252                           const struct GNUNET_CRYPTO_EcdsaPublicKey *key,
253                           const struct GNUNET_CRYPTO_EcdsaSignature *sig,
254                           uint64_t pow,
255                           GNUNET_REVOCATION_Callback func,
256                           void *func_cls)
257 {
258   struct GNUNET_REVOCATION_Handle *h
259     = GNUNET_new (struct GNUNET_REVOCATION_Handle);
260   struct GNUNET_MQ_MessageHandler handlers[] = {
261     GNUNET_MQ_hd_fixed_size (revocation_response,
262                              GNUNET_MESSAGE_TYPE_REVOCATION_REVOKE_RESPONSE,
263                              struct RevocationResponseMessage,
264                              h),
265     GNUNET_MQ_handler_end ()
266   };
267   unsigned long long matching_bits;
268   struct RevokeMessage *rm;
269   struct GNUNET_MQ_Envelope *env;
270
271   if ( (GNUNET_OK ==
272         GNUNET_CONFIGURATION_get_value_number (cfg,
273                                                "REVOCATION",
274                                                "WORKBITS",
275                                                &matching_bits)) &&
276        (GNUNET_YES !=
277         GNUNET_REVOCATION_check_pow (key,
278                                      pow,
279                                      (unsigned int) matching_bits)) )
280   {
281     GNUNET_break (0);
282     GNUNET_free (h);
283     return NULL;
284   }
285
286   h->mq = GNUNET_CLIENT_connecT (cfg,
287                                  "revocation",
288                                  handlers,
289                                  &revocation_mq_error_handler,
290                                  h);
291   if (NULL == h->mq)
292   {
293     GNUNET_free (h);
294     return NULL;
295   }
296   h->func = func;
297   h->func_cls = func_cls;
298   env = GNUNET_MQ_msg (rm,
299                        GNUNET_MESSAGE_TYPE_REVOCATION_REVOKE);
300   rm->reserved = htonl (0);
301   rm->proof_of_work = pow;
302   rm->purpose.purpose = htonl (GNUNET_SIGNATURE_PURPOSE_REVOCATION);
303   rm->purpose.size = htonl (sizeof (struct GNUNET_CRYPTO_EccSignaturePurpose) +
304                             sizeof (struct GNUNET_CRYPTO_EcdsaPublicKey));
305   rm->public_key = *key;
306   rm->signature = *sig;
307   GNUNET_MQ_send (h->mq,
308                   env);
309   return h;
310 }
311
312
313 /**
314  * Cancel key revocation.
315  *
316  * @param h operation to cancel
317  */
318 void
319 GNUNET_REVOCATION_revoke_cancel (struct GNUNET_REVOCATION_Handle *h)
320 {
321   if (NULL != h->mq)
322   {
323     GNUNET_MQ_destroy (h->mq);
324     h->mq = NULL;
325   }
326   GNUNET_free (h);
327 }
328
329
330 /**
331  * Calculate the 'proof-of-work' hash (an expensive hash).
332  *
333  * @param buf data to hash
334  * @param buf_len number of bytes in @a buf
335  * @param result where to write the resulting hash
336  */
337 static void
338 pow_hash (const void *buf,
339           size_t buf_len,
340           struct GNUNET_HashCode *result)
341 {
342   GNUNET_break (0 ==
343                 gcry_kdf_derive (buf, buf_len,
344                                  GCRY_KDF_SCRYPT,
345                                  1 /* subalgo */,
346                                  "gnunet-revocation-proof-of-work",
347                                  strlen ("gnunet-revocation-proof-of-work"),
348                                  2 /* iterations; keep cost of individual op small */,
349                                  sizeof (struct GNUNET_HashCode), result));
350 }
351
352
353 /**
354  * Count the leading zeroes in hash.
355  *
356  * @param hash to count leading zeros in
357  * @return the number of leading zero bits.
358  */
359 static unsigned int
360 count_leading_zeroes (const struct GNUNET_HashCode *hash)
361 {
362   unsigned int hash_count;
363
364   hash_count = 0;
365   while ((0 == GNUNET_CRYPTO_hash_get_bit (hash, hash_count)))
366     hash_count++;
367   return hash_count;
368 }
369
370
371 /**
372  * Check if the given proof-of-work value
373  * would be acceptable for revoking the given key.
374  *
375  * @param key key to check for
376  * @param pow proof of work value
377  * @param matching_bits how many bits must match (configuration)
378  * @return #GNUNET_YES if the @a pow is acceptable, #GNUNET_NO if not
379  */
380 int
381 GNUNET_REVOCATION_check_pow (const struct GNUNET_CRYPTO_EcdsaPublicKey *key,
382                              uint64_t pow,
383                              unsigned int matching_bits)
384 {
385   char buf[sizeof (struct GNUNET_CRYPTO_EcdsaPublicKey) +
386            sizeof (pow)] GNUNET_ALIGN;
387   struct GNUNET_HashCode result;
388
389   GNUNET_memcpy (buf, &pow, sizeof (pow));
390   GNUNET_memcpy (&buf[sizeof (pow)], key,
391           sizeof (struct GNUNET_CRYPTO_EcdsaPublicKey));
392   pow_hash (buf, sizeof (buf), &result);
393   return (count_leading_zeroes (&result) >=
394           matching_bits) ? GNUNET_YES : GNUNET_NO;
395 }
396
397
398 /**
399  * Create a revocation signature.
400  *
401  * @param key private key of the key to revoke
402  * @param sig where to write the revocation signature
403  */
404 void
405 GNUNET_REVOCATION_sign_revocation (const struct GNUNET_CRYPTO_EcdsaPrivateKey *key,
406                                    struct GNUNET_CRYPTO_EcdsaSignature *sig)
407 {
408   struct RevokeMessage rm;
409
410   rm.purpose.purpose = htonl (GNUNET_SIGNATURE_PURPOSE_REVOCATION);
411   rm.purpose.size = htonl (sizeof (struct GNUNET_CRYPTO_EccSignaturePurpose) +
412                            sizeof (struct GNUNET_CRYPTO_EcdsaPublicKey));
413   GNUNET_CRYPTO_ecdsa_key_get_public (key, &rm.public_key);
414   GNUNET_assert (GNUNET_OK ==
415                  GNUNET_CRYPTO_ecdsa_sign (key,
416                                          &rm.purpose,
417                                          sig));
418 }
419
420
421 /* end of revocation_api.c */