fix sign api for to address #6164
[oweals/gnunet.git] / src / regex / plugin_block_regex.c
1 /*
2      This file is part of GNUnet
3      Copyright (C) 2013 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 /**
22  * @file regex/plugin_block_regex.c
23  * @brief blocks used for regex storage and search
24  * @author Bartlomiej Polot
25  */
26 #include "platform.h"
27 #include "gnunet_block_plugin.h"
28 #include "gnunet_block_group_lib.h"
29 #include "block_regex.h"
30 #include "regex_block_lib.h"
31 #include "gnunet_signatures.h"
32
33
34 /**
35  * Number of bits we set per entry in the bloomfilter.
36  * Do not change!
37  */
38 #define BLOOMFILTER_K 16
39
40
41 /**
42  * How big is the BF we use for REGEX blocks?
43  */
44 #define REGEX_BF_SIZE 8
45
46
47 /**
48  * Create a new block group.
49  *
50  * @param ctx block context in which the block group is created
51  * @param type type of the block for which we are creating the group
52  * @param nonce random value used to seed the group creation
53  * @param raw_data optional serialized prior state of the group, NULL if unavailable/fresh
54  * @param raw_data_size number of bytes in @a raw_data, 0 if unavailable/fresh
55  * @param va variable arguments specific to @a type
56  * @return block group handle, NULL if block groups are not supported
57  *         by this @a type of block (this is not an error)
58  */
59 static struct GNUNET_BLOCK_Group *
60 block_plugin_regex_create_group (void *cls,
61                                  enum GNUNET_BLOCK_Type type,
62                                  uint32_t nonce,
63                                  const void *raw_data,
64                                  size_t raw_data_size,
65                                  va_list va)
66 {
67   unsigned int bf_size;
68   const char *guard;
69
70   guard = va_arg (va, const char *);
71   if (0 == strcmp (guard,
72                    "seen-set-size"))
73     bf_size = GNUNET_BLOCK_GROUP_compute_bloomfilter_size (va_arg (va, unsigned
74                                                                    int),
75                                                            BLOOMFILTER_K);
76   else if (0 == strcmp (guard,
77                         "filter-size"))
78     bf_size = va_arg (va, unsigned int);
79   else
80   {
81     GNUNET_break (0);
82     bf_size = REGEX_BF_SIZE;
83   }
84   GNUNET_break (NULL == va_arg (va, const char *));
85   return GNUNET_BLOCK_GROUP_bf_create (cls,
86                                        bf_size,
87                                        BLOOMFILTER_K,
88                                        type,
89                                        nonce,
90                                        raw_data,
91                                        raw_data_size);
92 }
93
94
95 /**
96  * Function called to validate a reply or a request of type
97  * #GNUNET_BLOCK_TYPE_REGEX.
98  * For request evaluation, pass "NULL" for the reply_block.
99  * Note that it is assumed that the reply has already been
100  * matched to the key (and signatures checked) as it would
101  * be done with the #GNUNET_BLOCK_get_key() function.
102  *
103  * @param cls closure
104  * @param type block type
105  * @param bg block group to evaluate against
106  * @param eo control flags
107  * @param query original query (hash)
108  * @param xquery extrended query data (can be NULL, depending on type)
109  * @param xquery_size number of bytes in @a xquery
110  * @param reply_block response to validate
111  * @param reply_block_size number of bytes in @a reply_block
112  * @return characterization of result
113  */
114 static enum GNUNET_BLOCK_EvaluationResult
115 evaluate_block_regex (void *cls,
116                       enum GNUNET_BLOCK_Type type,
117                       struct GNUNET_BLOCK_Group *bg,
118                       enum GNUNET_BLOCK_EvaluationOptions eo,
119                       const struct GNUNET_HashCode *query,
120                       const void *xquery,
121                       size_t xquery_size,
122                       const void *reply_block,
123                       size_t reply_block_size)
124 {
125   struct GNUNET_HashCode chash;
126
127   if (NULL == reply_block)
128   {
129     if (0 != xquery_size)
130     {
131       const char *s;
132
133       s = (const char *) xquery;
134       if ('\0' != s[xquery_size - 1])     /* must be valid 0-terminated string */
135       {
136         GNUNET_break_op (0);
137         return GNUNET_BLOCK_EVALUATION_REQUEST_INVALID;
138       }
139     }
140     return GNUNET_BLOCK_EVALUATION_REQUEST_VALID;
141   }
142   if (0 != xquery_size)
143   {
144     const char *s;
145
146     s = (const char *) xquery;
147     if ('\0' != s[xquery_size - 1])   /* must be valid 0-terminated string */
148     {
149       GNUNET_break_op (0);
150       return GNUNET_BLOCK_EVALUATION_REQUEST_INVALID;
151     }
152   }
153   else if (NULL != query)
154   {
155     /* xquery is required for regex GETs, at least an empty string */
156     GNUNET_break_op (0);
157     GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "type %d, query %p, xquery %p\n",
158                 type, query, xquery);
159     return GNUNET_BLOCK_EVALUATION_REQUEST_INVALID;
160   }
161   switch (REGEX_BLOCK_check (reply_block,
162                              reply_block_size,
163                              query,
164                              xquery))
165   {
166   case GNUNET_SYSERR:
167     GNUNET_break_op (0);
168     return GNUNET_BLOCK_EVALUATION_RESULT_INVALID;
169
170   case GNUNET_NO:
171     /* xquery missmatch, can happen */
172     return GNUNET_BLOCK_EVALUATION_RESULT_IRRELEVANT;
173
174   default:
175     break;
176   }
177   GNUNET_CRYPTO_hash (reply_block,
178                       reply_block_size,
179                       &chash);
180   if (GNUNET_YES ==
181       GNUNET_BLOCK_GROUP_bf_test_and_set (bg,
182                                           &chash))
183     return GNUNET_BLOCK_EVALUATION_OK_DUPLICATE;
184   return GNUNET_BLOCK_EVALUATION_OK_MORE;
185 }
186
187
188 /**
189  * Function called to validate a reply or a request of type
190  * #GNUNET_BLOCK_TYPE_REGEX_ACCEPT.
191  * For request evaluation, pass "NULL" for the reply_block.
192  * Note that it is assumed that the reply has already been
193  * matched to the key (and signatures checked) as it would
194  * be done with the #GNUNET_BLOCK_get_key() function.
195  *
196  * @param cls closure
197  * @param type block type
198  * @param bg block group to evaluate against
199  * @param eo control flags
200  * @param query original query (hash)
201  * @param xquery extrended query data (can be NULL, depending on type)
202  * @param xquery_size number of bytes in @a xquery
203  * @param reply_block response to validate
204  * @param reply_block_size number of bytes in @a reply_block
205  * @return characterization of result
206  */
207 static enum GNUNET_BLOCK_EvaluationResult
208 evaluate_block_regex_accept (void *cls,
209                              enum GNUNET_BLOCK_Type type,
210                              struct GNUNET_BLOCK_Group *bg,
211                              enum GNUNET_BLOCK_EvaluationOptions eo,
212                              const struct GNUNET_HashCode *query,
213                              const void *xquery,
214                              size_t xquery_size, const void *reply_block,
215                              size_t reply_block_size)
216 {
217   const struct RegexAcceptBlock *rba;
218   struct GNUNET_HashCode chash;
219
220   if (0 != xquery_size)
221   {
222     GNUNET_break_op (0);
223     return GNUNET_BLOCK_EVALUATION_REQUEST_INVALID;
224   }
225   if (NULL == reply_block)
226     return GNUNET_BLOCK_EVALUATION_REQUEST_VALID;
227   if (sizeof(struct RegexAcceptBlock) != reply_block_size)
228   {
229     GNUNET_break_op (0);
230     return GNUNET_BLOCK_EVALUATION_RESULT_INVALID;
231   }
232   rba = reply_block;
233   if (ntohl (rba->purpose.size) !=
234       sizeof(struct GNUNET_CRYPTO_EccSignaturePurpose)
235       + sizeof(struct GNUNET_TIME_AbsoluteNBO)
236       + sizeof(struct GNUNET_HashCode))
237   {
238     GNUNET_break_op (0);
239     return GNUNET_BLOCK_EVALUATION_RESULT_INVALID;
240   }
241   if (0 == GNUNET_TIME_absolute_get_remaining (GNUNET_TIME_absolute_ntoh (
242                                                  rba->expiration_time)).
243       rel_value_us)
244   {
245     /* technically invalid, but can happen without an error, so
246        we're nice by reporting it as a 'duplicate' */
247     return GNUNET_BLOCK_EVALUATION_OK_DUPLICATE;
248   }
249   if (GNUNET_OK !=
250       GNUNET_CRYPTO_eddsa_verify_ (GNUNET_SIGNATURE_PURPOSE_REGEX_ACCEPT,
251                                    &rba->purpose,
252                                    &rba->signature,
253                                    &rba->peer.public_key))
254   {
255     GNUNET_break_op (0);
256     return GNUNET_BLOCK_EVALUATION_RESULT_INVALID;
257   }
258   GNUNET_CRYPTO_hash (reply_block,
259                       reply_block_size,
260                       &chash);
261   if (GNUNET_YES ==
262       GNUNET_BLOCK_GROUP_bf_test_and_set (bg,
263                                           &chash))
264     return GNUNET_BLOCK_EVALUATION_OK_DUPLICATE;
265   return GNUNET_BLOCK_EVALUATION_OK_MORE;
266 }
267
268
269 /**
270  * Function called to validate a reply or a request.  For
271  * request evaluation, simply pass "NULL" for the reply_block.
272  * Note that it is assumed that the reply has already been
273  * matched to the key (and signatures checked) as it would
274  * be done with the #GNUNET_BLOCK_get_key() function.
275  *
276  * @param cls closure
277  * @param ctx block context
278  * @param type block type
279  * @param bg group to evaluate against
280  * @param eo control flags
281  * @param query original query (hash)
282  * @param xquery extrended query data (can be NULL, depending on type)
283  * @param xquery_size number of bytes in xquery
284  * @param reply_block response to validate
285  * @param reply_block_size number of bytes in reply block
286  * @return characterization of result
287  */
288 static enum GNUNET_BLOCK_EvaluationResult
289 block_plugin_regex_evaluate (void *cls,
290                              struct GNUNET_BLOCK_Context *ctx,
291                              enum GNUNET_BLOCK_Type type,
292                              struct GNUNET_BLOCK_Group *bg,
293                              enum GNUNET_BLOCK_EvaluationOptions eo,
294                              const struct GNUNET_HashCode *query,
295                              const void *xquery,
296                              size_t xquery_size,
297                              const void *reply_block,
298                              size_t reply_block_size)
299 {
300   enum GNUNET_BLOCK_EvaluationResult result;
301
302   switch (type)
303   {
304   case GNUNET_BLOCK_TYPE_REGEX:
305     result = evaluate_block_regex (cls,
306                                    type,
307                                    bg,
308                                    eo,
309                                    query,
310                                    xquery, xquery_size,
311                                    reply_block, reply_block_size);
312     break;
313
314   case GNUNET_BLOCK_TYPE_REGEX_ACCEPT:
315     result = evaluate_block_regex_accept (cls,
316                                           type,
317                                           bg,
318                                           eo,
319                                           query,
320                                           xquery, xquery_size,
321                                           reply_block, reply_block_size);
322     break;
323
324   default:
325     result = GNUNET_BLOCK_EVALUATION_TYPE_NOT_SUPPORTED;
326   }
327   return result;
328 }
329
330
331 /**
332  * Function called to obtain the key for a block.
333  *
334  * @param cls closure
335  * @param type block type
336  * @param block block to get the key for
337  * @param block_size number of bytes in @a block
338  * @param key set to the key (query) for the given block
339  * @return #GNUNET_OK on success, #GNUNET_SYSERR if type not supported
340  *         (or if extracting a key from a block of this type does not work)
341  */
342 static int
343 block_plugin_regex_get_key (void *cls,
344                             enum GNUNET_BLOCK_Type type,
345                             const void *block,
346                             size_t block_size,
347                             struct GNUNET_HashCode *key)
348 {
349   switch (type)
350   {
351   case GNUNET_BLOCK_TYPE_REGEX:
352     if (GNUNET_OK !=
353         REGEX_BLOCK_get_key (block, block_size,
354                              key))
355     {
356       GNUNET_break_op (0);
357       return GNUNET_NO;
358     }
359     return GNUNET_OK;
360
361   case GNUNET_BLOCK_TYPE_REGEX_ACCEPT:
362     if (sizeof(struct RegexAcceptBlock) != block_size)
363     {
364       GNUNET_break_op (0);
365       return GNUNET_NO;
366     }
367     *key = ((struct RegexAcceptBlock *) block)->key;
368     return GNUNET_OK;
369
370   default:
371     GNUNET_break (0);
372     return GNUNET_SYSERR;
373   }
374 }
375
376
377 /**
378  * Entry point for the plugin.
379  */
380 void *
381 libgnunet_plugin_block_regex_init (void *cls)
382 {
383   static enum GNUNET_BLOCK_Type types[] = {
384     GNUNET_BLOCK_TYPE_REGEX,
385     GNUNET_BLOCK_TYPE_REGEX_ACCEPT,
386     GNUNET_BLOCK_TYPE_ANY       /* end of list */
387   };
388   struct GNUNET_BLOCK_PluginFunctions *api;
389
390   api = GNUNET_new (struct GNUNET_BLOCK_PluginFunctions);
391   api->evaluate = &block_plugin_regex_evaluate;
392   api->get_key = &block_plugin_regex_get_key;
393   api->create_group = &block_plugin_regex_create_group;
394   api->types = types;
395   return api;
396 }
397
398
399 /**
400  * Exit point from the plugin.
401  */
402 void *
403 libgnunet_plugin_block_regex_done (void *cls)
404 {
405   struct GNUNET_BLOCK_PluginFunctions *api = cls;
406
407   GNUNET_free (api);
408   return NULL;
409 }
410
411
412 /* end of plugin_block_regex.c */