-keep track of messages passed to mq
[oweals/gnunet.git] / src / sensor / sensor_util_lib_crypto.c
1 /*
2      This file is part of GNUnet.
3      Copyright (C)
4
5      GNUnet is free software; you can redistribute it and/or modify
6      it under the terms of the GNU General Public License 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 License for more details.
14
15      You should have received a copy of the GNU General Public License
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 /**
22  * @file sensor/sensor_util_lib_crypto.c
23  * @brief senor utilities - crpyto related functions
24  * @author Omar Tarabai
25  */
26 #include <inttypes.h>
27 #include "platform.h"
28 #include "gnunet_util_lib.h"
29 #include "gnunet_sensor_util_lib.h"
30 #include "gnunet_signatures.h"
31
32 #define LOG(kind,...) GNUNET_log_from (kind, "sensor-util-crypto",__VA_ARGS__)
33
34 /**
35  * Context of an operation performed by #GNUNET_SENSOR_crypto_pow_sign()
36  */
37 struct GNUNET_SENSOR_crypto_pow_context
38 {
39
40   /**
41    * Proof-of-work value
42    */
43   uint64_t pow;
44
45   /**
46    * Private key to be used for signing
47    */
48   struct GNUNET_CRYPTO_EddsaPrivateKey private_key;
49
50   /**
51    * Number of leading zeros required in the result hash
52    */
53   int matching_bits;
54
55   /**
56    * Callback function to call with the result
57    */
58   GNUNET_SENSOR_UTIL_pow_callback callback;
59
60   /**
61    * Closure for callback
62    */
63   void *callback_cls;
64
65   /**
66    * Task that calculates the proof-of-work
67    */
68   struct GNUNET_SCHEDULER_Task * calculate_pow_task;
69
70   /**
71    * Size of msg (allocated after this struct)
72    */
73   size_t msg_size;
74
75   /**
76    * Timestamp of the message
77    */
78   struct GNUNET_TIME_Absolute timestamp;
79
80   /**
81    * Public key of the peer sending this message
82    */
83   struct GNUNET_CRYPTO_EddsaPublicKey public_key;
84
85 };
86
87
88 /**
89  * Calculate the scrypt hash
90  */
91 static void
92 pow_hash (const void *buf, size_t buf_len, struct GNUNET_HashCode *result)
93 {
94   GNUNET_break (0 ==
95                 gcry_kdf_derive (buf, buf_len, GCRY_KDF_SCRYPT,
96                                  1 /* subalgo */ ,
97                                  "gnunet-sensor-util-proof-of-work",
98                                  strlen ("gnunet-sensor-util-proof-of-work"), 2
99                                  /* iterations; keep cost of individual op small */
100                                  , sizeof (struct GNUNET_HashCode), result));
101 }
102
103
104 /**
105  * Count the leading zeroes in hash.
106  *
107  * @param hash to count leading zeros in
108  * @return the number of leading zero bits.
109  */
110 static unsigned int
111 count_leading_zeroes (const struct GNUNET_HashCode *hash)
112 {
113   unsigned int hash_count;
114
115   hash_count = 0;
116   while ((0 == GNUNET_CRYPTO_hash_get_bit (hash, hash_count)))
117     hash_count++;
118   return hash_count;
119 }
120
121
122 /**
123  * Check if the given proof-of-work is valid
124  */
125 static int
126 check_pow (void *msg, size_t msg_size, uint64_t pow, int matching_bits)
127 {
128   char buf[msg_size + sizeof (pow)] GNUNET_ALIGN;
129   struct GNUNET_HashCode result;
130
131   memcpy (buf, &pow, sizeof (pow));
132   memcpy (&buf[sizeof (pow)], msg, msg_size);
133   pow_hash (buf, sizeof (buf), &result);
134   return (count_leading_zeroes (&result) >=
135           matching_bits) ? GNUNET_YES : GNUNET_NO;
136 }
137
138
139 /**
140  * Task that checks if pow is correct, otherwise increments and reschedules itself
141  */
142 static void
143 calculate_pow (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc)
144 {
145   struct GNUNET_SENSOR_crypto_pow_context *cx = cls;
146   struct GNUNET_SENSOR_crypto_pow_block *result_block;
147   GNUNET_SENSOR_UTIL_pow_callback callback;
148   void *callback_cls;
149   int sign_result;
150
151   if (0 == cx->pow % 1000)
152     LOG (GNUNET_ERROR_TYPE_DEBUG, "Checking pow %" PRIu64 ".\n", cx->pow);
153   if (GNUNET_YES ==
154       check_pow (&cx->timestamp,
155                  sizeof (struct GNUNET_CRYPTO_EddsaPublicKey) +
156                  sizeof (struct GNUNET_TIME_Absolute) + cx->msg_size, cx->pow,
157                  cx->matching_bits))
158   {
159     LOG (GNUNET_ERROR_TYPE_DEBUG, "Found pow %" PRIu64 ".\n", cx->pow);
160     cx->calculate_pow_task = NULL;
161     result_block =
162         GNUNET_malloc (sizeof (struct GNUNET_SENSOR_crypto_pow_block) +
163                        cx->msg_size);
164     result_block->msg_size = cx->msg_size;
165     result_block->pow = cx->pow;
166     result_block->timestamp = cx->timestamp;
167     result_block->public_key = cx->public_key;
168     result_block->purpose.purpose =
169         htonl (GNUNET_SIGNATURE_PURPOSE_SENSOR_ANOMALY_REPORT);
170     result_block->purpose.size =
171         htonl (sizeof (struct GNUNET_CRYPTO_EccSignaturePurpose) +
172                sizeof (struct GNUNET_TIME_Absolute) +
173                sizeof (struct GNUNET_CRYPTO_EddsaPublicKey) + cx->msg_size);
174     memcpy (&result_block[1], &cx[1], cx->msg_size);
175     sign_result =
176         GNUNET_CRYPTO_eddsa_sign (&cx->private_key, &result_block->purpose,
177                                   &result_block->signature);
178     callback = cx->callback;
179     callback_cls = cx->callback_cls;
180     GNUNET_SENSOR_crypto_pow_sign_cancel (cx);
181     if (NULL != callback)
182       callback (callback_cls, (GNUNET_OK == sign_result) ? result_block : NULL);
183     GNUNET_free (result_block);
184     return;
185   }
186   cx->pow++;
187   cx->calculate_pow_task = GNUNET_SCHEDULER_add_now (&calculate_pow, cx);
188 }
189
190
191 /**
192  * Cancel an operation started by #GNUNET_SENSOR_crypto_pow_sign().
193  * Call only before callback function passed to #GNUNET_SENSOR_crypto_pow_sign()
194  * is called with the result.
195  */
196 void
197 GNUNET_SENSOR_crypto_pow_sign_cancel (struct GNUNET_SENSOR_crypto_pow_context
198                                       *cx)
199 {
200   if (NULL != cx->calculate_pow_task)
201   {
202     GNUNET_SCHEDULER_cancel (cx->calculate_pow_task);
203     cx->calculate_pow_task = NULL;
204   }
205   GNUNET_free (cx);
206   cx = NULL;
207 }
208
209
210 /**
211  * Calculate proof-of-work and sign a message.
212  * The result of all operations will be returned via the callback passed to this
213  * function. Note that the payload (msg) is copied to the result block.
214  *
215  * @param msg Message to calculate pow and sign
216  * @param msg_size size of msg
217  * @param timestamp Timestamp to add to the message to protect against replay attacks
218  * @param public_key Public key of the origin peer, to protect against redirect attacks
219  * @param private_key Private key of the origin peer to sign the result
220  * @param matching_bits Number of leading zeros required in the result hash
221  * @param callback Callback function to call with the result
222  * @param callback_cls Closure for callback
223  * @return Operation context
224  */
225 struct GNUNET_SENSOR_crypto_pow_context *
226 GNUNET_SENSOR_crypto_pow_sign (void *msg, size_t msg_size,
227                                struct GNUNET_TIME_Absolute *timestamp,
228                                struct GNUNET_CRYPTO_EddsaPublicKey *public_key,
229                                struct GNUNET_CRYPTO_EddsaPrivateKey
230                                *private_key, int matching_bits,
231                                GNUNET_SENSOR_UTIL_pow_callback callback,
232                                void *callback_cls)
233 {
234   struct GNUNET_SENSOR_crypto_pow_context *cx;
235
236   cx = GNUNET_malloc (sizeof (struct GNUNET_SENSOR_crypto_pow_context) +
237                       msg_size);
238
239   cx->timestamp = *timestamp;
240   cx->public_key = *public_key;
241   cx->msg_size = msg_size;
242   memcpy (&cx[1], msg, msg_size);
243   cx->pow = 0;
244   cx->private_key = *private_key;
245   cx->matching_bits = matching_bits;
246   cx->callback = callback;
247   cx->callback_cls = callback_cls;
248   cx->calculate_pow_task = GNUNET_SCHEDULER_add_now (&calculate_pow, cx);
249   return cx;
250 }
251
252
253 /**
254  * Verify that proof-of-work and signature in the given block are valid.
255  * If all valid, a pointer to the payload within the block is set and the size
256  * of the payload is returned.
257  *
258  * **VERY IMPORTANT** : You will still need to verify the timestamp yourself.
259  *
260  * @param block The block received and needs to be verified
261  * @param matching_bits Number of leading zeros in the hash used to verify pow
262  * @param public_key Public key of the peer that sent this block
263  * @param payload Where to store the pointer to the payload
264  * @return Size of the payload, 0 on error
265  */
266 size_t
267 GNUNET_SENSOR_crypto_verify_pow_sign (struct GNUNET_SENSOR_crypto_pow_block *
268                                       block, int matching_bits,
269                                       struct GNUNET_CRYPTO_EddsaPublicKey *
270                                       public_key, void **payload)
271 {
272   /* Check public key */
273   if (0 !=
274       memcmp (public_key, &block->public_key,
275               sizeof (struct GNUNET_CRYPTO_EddsaPublicKey)))
276   {
277     LOG (GNUNET_ERROR_TYPE_WARNING, "Public key mismatch.\n");
278     return 0;
279   }
280   /* Check signature */
281   if (GNUNET_OK !=
282       GNUNET_CRYPTO_eddsa_verify
283       (GNUNET_SIGNATURE_PURPOSE_SENSOR_ANOMALY_REPORT, &block->purpose,
284        &block->signature, public_key))
285   {
286     LOG (GNUNET_ERROR_TYPE_WARNING, "Invalid signature.\n");
287     return 0;
288   }
289   /* Check pow */
290   if (GNUNET_NO ==
291       check_pow (&block->timestamp,
292                  sizeof (struct GNUNET_TIME_Absolute) +
293                  sizeof (struct GNUNET_CRYPTO_EddsaPublicKey) + block->msg_size,
294                  block->pow, matching_bits))
295   {
296     LOG (GNUNET_ERROR_TYPE_WARNING, "Invalid proof-of-work.\n");
297     return 0;
298   }
299   *payload = &block[1];
300   return block->msg_size;
301 }