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