c11 safe string handling support
[vpp.git] / src / plugins / ioam / lib-pot / pot_util.c
1 /* 
2  * Copyright (c) 2016 Cisco and/or its affiliates.
3  * Licensed under the Apache License, Version 2.0 (the "License");
4  * you may not use this file except in compliance with the License.
5  * You may obtain a copy of the License at:
6  *
7  *     http://www.apache.org/licenses/LICENSE-2.0
8  *
9  * Unless required by applicable law or agreed to in writing, software
10  * distributed under the License is distributed on an "AS IS" BASIS,
11  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12  * See the License for the specific language governing permissions and
13  * limitations under the License.
14  */
15 #include <vnet/vnet.h>
16 #include <stdint.h>
17 #include <time.h>
18 #include <string.h>
19 #include <vppinfra/mem.h>
20 #include "math64.h"
21 #include "pot_util.h"
22
23 pot_main_t pot_main;
24
25 static void pot_profile_cleanup(pot_profile *profile);
26
27 static void pot_main_profiles_reset (void)
28 {
29     pot_main_t *sm = &pot_main;
30     int i = 0;
31
32     for (i = 0; i < MAX_POT_PROFILES; i++)
33     {
34       pot_profile_cleanup(&(sm->profile_list[i]));
35     }
36     sm->active_profile_id = 0;
37     if (sm->profile_list_name)
38         vec_free(sm->profile_list_name);
39     sm->profile_list_name = NULL;
40 }
41
42 int pot_util_init (void)
43 {
44     pot_main_profiles_reset();
45     
46     return(0);
47 }
48
49 static void pot_profile_init(pot_profile * new, u8 id)
50 {
51     if (new)
52     {
53         clib_memset(new, 0, sizeof(pot_profile));
54         new->id = id;
55     }
56 }
57
58 pot_profile *pot_profile_find(u8 id)
59 {
60     pot_main_t *sm = &pot_main;
61
62     if (id < MAX_POT_PROFILES)
63     {
64         return (&(sm->profile_list[id]));
65     }
66     return (NULL);
67 }
68 static int pot_profile_name_equal (u8 *name0, u8 *name1)
69 {
70     int len0, len1;
71
72     len0 = vec_len (name0);
73     len1 = vec_len (name1);
74     if (len0 != len1)
75         return(0);
76     return (0==strncmp ((char *) name0, (char *)name1, len0));
77 }
78
79 int pot_profile_list_is_enabled (u8 *name)
80 {
81     pot_main_t *sm = &pot_main;
82     return (pot_profile_name_equal(sm->profile_list_name, name));
83 }
84
85 void pot_profile_list_init(u8 * profile_list_name)
86 {
87     pot_main_t *sm = &pot_main;
88     int i = 0;
89
90     /* If it is the same profile list skip reset */
91     if (pot_profile_name_equal(sm->profile_list_name, profile_list_name))
92     {
93       return;
94     }
95
96     pot_main_profiles_reset();
97     if (vec_len(profile_list_name))
98       sm->profile_list_name = (u8 *)vec_dup(profile_list_name);
99     else
100       sm->profile_list_name = 0;
101     sm->active_profile_id = 0;
102     
103     for (i = 0; i < MAX_POT_PROFILES; i++)
104     {
105       pot_profile_init(&(sm->profile_list[i]), i);
106     }
107 }
108
109 static void pot_profile_cleanup(pot_profile * profile)
110 {
111     u16 id = profile->id;
112
113     clib_memset(profile, 0, sizeof(pot_profile));
114     profile->id = id;           /* Restore id alone */
115 }
116
117 int pot_profile_create(pot_profile * profile, u64 prime,
118     u64 poly2, u64 lpc, u64 secret_share)
119 {
120     if (profile && !profile->in_use)
121     {
122         pot_profile_cleanup(profile);
123         profile->prime = prime;
124         profile->primeinv = 1.0 / prime;
125         profile->lpc = lpc;
126         profile->poly_pre_eval = poly2;
127         profile->secret_share = secret_share;
128         profile->total_pkts_using_this_profile = 0;
129         profile->valid = 1;
130         return(0);
131     }
132     
133     return(-1);
134 }
135
136 int pot_set_validator(pot_profile * profile, u64 key)
137 {
138     if (profile && !profile->in_use)
139     {
140         profile->validator = 1;
141         profile->secret_key = key;
142         return(0);
143     }
144     return(-1);
145 }
146
147 always_inline u64 pot_update_cumulative_inline(u64 cumulative, u64 random,
148     u64 secret_share, u64 prime, u64 lpc, u64 pre_split, double prime_inv)
149 {
150     u64 share_random = 0;
151     u64 cumulative_new = 0;
152
153     /* 
154      * calculate split share for random
155      */
156     share_random = add64_mod(pre_split, random, prime, prime_inv);
157
158     /* 
159      * lpc * (share_secret + share_random)
160      */
161     share_random = add64_mod(share_random, secret_share, prime, prime_inv);
162     share_random = mul64_mod(share_random, lpc, prime, prime_inv);
163
164     cumulative_new = add64_mod(cumulative, share_random, prime, prime_inv);
165
166     return (cumulative_new);
167 }
168
169 u64 pot_update_cumulative(pot_profile * profile, u64 cumulative, u64 random)
170 {
171     if (profile && profile->valid != 0)
172     {
173         return (pot_update_cumulative_inline(cumulative, random, profile->secret_share,
174                 profile->prime, profile->lpc, profile->poly_pre_eval,
175                 profile->primeinv));
176     }
177     return (0);
178 }
179
180 always_inline u8 pot_validate_inline(u64 secret, u64 prime, double prime_inv,
181     u64 cumulative, u64 random)
182 {
183     if (cumulative == (random + secret))
184     {
185         return (1);
186     }
187     else if (cumulative == add64_mod(random, secret, prime, prime_inv))
188     {
189         return (1);
190     }
191     return (0);
192 }
193
194 /* 
195  * return True if the cumulative matches secret from a profile
196  */
197 u8 pot_validate(pot_profile * profile, u64 cumulative, u64 random)
198 {
199     if (profile && profile->validator)
200     {
201         return (pot_validate_inline(profile->secret_key, profile->prime,
202                 profile->primeinv, cumulative, random));
203     }
204     return (0);
205 }
206
207 /* 
208  * Utility function to get random number per pack
209  */
210 u64 pot_generate_random(pot_profile * profile)
211 {
212     u64 random = 0;
213     int32_t second_half;
214     static u32 seed = 0;
215
216     if (PREDICT_FALSE(!seed))
217         seed = random_default_seed();
218
219     /* 
220      * Upper 4 bytes seconds
221      */
222     random = (u64) time(NULL);
223
224     random &= 0xffffffff;
225     random = random << 32;
226     /* 
227      * Lower 4 bytes random number
228      */
229     second_half = random_u32(&seed);
230
231     random |= second_half;
232
233     if (PREDICT_TRUE(profile != NULL))
234     {
235         random &= profile->bit_mask;
236     }
237     return (random);
238 }
239
240 int pot_profile_set_bit_mask(pot_profile * profile, u16 bits)
241 {
242     int sizeInBits;
243
244     if (profile && !profile->in_use)
245     {
246         sizeInBits = sizeof(profile->bit_mask) * 8;
247         profile->bit_mask =
248             (bits >=
249             sizeInBits ? (u64) - 1 : (u64) ((u64) 1 << (u64) bits) - 1);
250         return(0);
251     }
252     return(-1);
253 }
254
255 clib_error_t *clear_pot_profile_command_fn(vlib_main_t * vm,
256     unformat_input_t * input, vlib_cli_command_t * cmd)
257 {
258
259     pot_main_profiles_reset();
260     
261     return 0;
262 }
263
264 void clear_pot_profiles()
265 {
266     clear_pot_profile_command_fn(0, 0, 0);
267 }
268
269 VLIB_CLI_COMMAND(clear_pot_profile_command) =
270 {
271 .path = "clear pot profile",
272 .short_help = "clear pot profile [<index>|all]",
273 .function = clear_pot_profile_command_fn,
274 };
275
276 static clib_error_t *set_pot_profile_command_fn(vlib_main_t * vm,
277     unformat_input_t * input, vlib_cli_command_t * cmd)
278 {
279     u64 prime;
280     u64 secret_share;
281     u64 secret_key;
282     u8 validator = 0;
283     u32 profile_id = ~0;
284     u32 bits;
285     u64 lpc = 0, poly2 = 0;
286     pot_profile *profile = NULL;
287     u8 *profile_list_name = NULL;
288     
289     bits = MAX_BITS;
290
291     while (unformat_check_input(input) != UNFORMAT_END_OF_INPUT)
292     {
293         if (unformat(input, "name %s",
294                      &profile_list_name));
295         else if (unformat(input, "id %d", &profile_id))
296             ;
297         else if (unformat(input, "validate-key 0x%Lx", &secret_key))
298             validator = 1;
299         else if (unformat(input, "prime-number 0x%Lx", &prime))
300             ;
301         else if (unformat(input, "secret_share 0x%Lx", &secret_share))
302             ;
303         else if (unformat(input, "polynomial2 0x%Lx", &poly2))
304             ;
305         else if (unformat(input, "lpc 0x%Lx", &lpc))
306             ;
307         else if (unformat(input, "bits-in-random %d", &bits))
308         {
309             if (bits > MAX_BITS)
310                 bits = MAX_BITS;
311         }
312         else
313           break;
314     }
315     if (profile_list_name == 0)
316     {
317         return clib_error_return(0, "Name cannot be null");
318     }   
319     pot_profile_list_init(profile_list_name);
320     profile = pot_profile_find(profile_id);
321
322     if (profile)
323     {
324         pot_profile_create(profile, prime, poly2, lpc, secret_share);
325         if (validator)
326             pot_set_validator(profile, secret_key);
327         pot_profile_set_bit_mask(profile, bits);
328     }
329     vec_free(profile_list_name);
330     return 0;
331 }
332
333 VLIB_CLI_COMMAND(set_pot_profile_command) =
334 {
335 .path = "set pot profile",
336 .short_help = "set pot profile name <string> id [0-1] [validator-key 0xu64] \
337                   prime-number 0xu64 secret_share 0xu64 lpc 0xu64 \
338                   polynomial2 0xu64 bits-in-random [0-64] ",
339 .function = set_pot_profile_command_fn,
340 };
341
342 static clib_error_t *set_pot_profile_activate_command_fn(vlib_main_t * vm,
343     unformat_input_t * input, vlib_cli_command_t * cmd)
344 {
345     pot_main_t *sm = &pot_main;
346     u8 *profile_list_name = NULL;
347     u32 id = 0;
348     clib_error_t *result = NULL;
349     
350     while (unformat_check_input(input) != UNFORMAT_END_OF_INPUT)
351     {
352         if (unformat(input, "name %s",
353                      &profile_list_name));
354         else if (unformat(input, "id %d", &id))
355             ;
356         else
357             return clib_error_return(0, "unknown input `%U'",
358                 format_unformat_error, input);
359     }
360     if (profile_list_name == 0)
361     {
362         return clib_error_return(0, "Name cannot be null");
363     }
364
365     if (!pot_profile_list_is_enabled(profile_list_name)) {
366         result = clib_error_return(0, "%s list is not enabled, profile in use %s",
367                                  profile_list_name, sm->profile_list_name);
368     } else if (0 != pot_profile_set_active((u8)id)) {
369         result = clib_error_return(0, "Profile %d not defined in %s",
370                                  id, sm->profile_list_name);
371     }
372     vec_free(profile_list_name);
373     return result;
374 }
375
376 VLIB_CLI_COMMAND(set_pot_profile_activate_command) =
377 {
378 .path = "set pot profile-active",
379 .short_help = "set pot profile-active name <string> id [0-1]",
380 .function = set_pot_profile_activate_command_fn,
381 };
382
383 static clib_error_t *show_pot_profile_command_fn(vlib_main_t * vm,
384     unformat_input_t * input, vlib_cli_command_t * cmd)
385 {
386     pot_main_t *sm = &pot_main;
387     pot_profile *p = NULL;
388     u16 i;
389     u8 *s = 0;
390
391     if (vec_len(sm->profile_list_name) == 0)
392     {
393         s = format(s, "POT Profiles not configured\n");
394         vlib_cli_output(vm, "%v", s);
395         return 0;
396     }
397     s = format(s, "Profile list in use  : %s\n",sm->profile_list_name);
398     for (i = 0; i < MAX_POT_PROFILES; i++)
399     {
400         p = pot_profile_find(i);
401         if (p->valid == 0)
402             continue;
403         s = format(s, "POT Profile at index: %d\n", i);
404         s = format(s, "                 Id : %d\n", p->id);
405         s = format(s, "          Validator : %s (%d)\n",
406             (p->validator) ? "True" : "False", p->validator);
407         if (p->validator == 1)
408             s = format(s, "         Secret key : 0x%Lx (%Ld)\n",
409                 p->secret_key, p->secret_key);
410         s = format(s, "       Secret share : 0x%Lx (%Ld)\n",
411             p->secret_share, p->secret_share);
412         s = format(s, "       Prime number : 0x%Lx (%Ld)\n",
413             p->prime, p->prime);
414         s = format(s, "2nd polynomial(eval) : 0x%Lx (%Ld)\n",
415             p->poly_pre_eval, p->poly_pre_eval);
416         s = format(s, "                 LPC : 0x%Lx (%Ld)\n", p->lpc, p->lpc);
417
418         s = format(s, "           Bit mask : 0x%Lx (%Ld)\n",
419             p->bit_mask, p->bit_mask);
420     }
421
422     p = pot_profile_find(sm->active_profile_id);
423
424     if (p && p->valid && p->in_use) {
425         s = format(s, "\nProfile index in use: %d\n", sm->active_profile_id);
426         s = format(s, "Pkts passed : 0x%Lx (%Ld)\n",
427                    p->total_pkts_using_this_profile,
428                    p->total_pkts_using_this_profile);
429         if (pot_is_decap(p))
430             s = format(s, "  This is Decap node.  \n");
431     } else {
432         s = format(s, "\nProfile index in use: None\n");
433     }
434     vlib_cli_output(vm, "%v", s);
435     vec_free(s);
436
437     return 0;
438 }
439
440 VLIB_CLI_COMMAND(show_pot_profile_command) =
441 {
442 .path = "show pot profile",
443 .short_help = "show pot profile",
444 .function = show_pot_profile_command_fn,
445 };