BSL v0.0.0
AMMOS Bundle Protocol Security Library (BSL)
Loading...
Searching...
No Matches
bsl_mock_bpa_eidpat.c
1/*
2 * Copyright (c) 2025 The Johns Hopkins University Applied Physics
3 * Laboratory LLC.
4 *
5 * This file is part of the Bundle Protocol Security Library (BSL).
6 *
7 * Licensed under the Apache License, Version 2.0 (the "License");
8 * you may not use this file except in compliance with the License.
9 * You may obtain a copy of the License at
10 * http://www.apache.org/licenses/LICENSE-2.0
11 * Unless required by applicable law or agreed to in writing, software
12 * distributed under the License is distributed on an "AS IS" BASIS,
13 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14 * See the License for the specific language governing permissions and
15 * limitations under the License.
16 *
17 * This work was performed for the Jet Propulsion Laboratory, California
18 * Institute of Technology, sponsored by the United States Government under
19 * the prime contract 80NM0018D0004 between the Caltech and NASA under
20 * subcontract 1700763.
21 */
22#include "bsl_mock_bpa_eidpat.h"
23#include <BPSecLib_Private.h>
24#include <strings.h>
25
26int bsl_eidpat_numrange_seg_cmp(const bsl_eidpat_numrange_seg_t *left, const bsl_eidpat_numrange_seg_t *right)
27{
28 if (!left || !right)
29 {
30 // not valid
31 return 0;
32 }
33 if (left->last < right->last)
34 {
35 return -1;
36 }
37 if (left->last > right->last)
38 {
39 return 1;
40 }
41 return 0;
42}
43
44bool bsl_eidpat_numrange_seg_overlap(const bsl_eidpat_numrange_seg_t *left, const bsl_eidpat_numrange_seg_t *right)
45{
46 if (!left || !right)
47 {
48 // not valid
49 return false;
50 }
51
52 uint64_t max_first = (left->first > right->first) ? left->first : right->first;
53 uint64_t min_last = (left->last < right->last) ? left->last : right->last;
54 return (max_first <= min_last);
55}
56
57void bsl_eidpat_numcomp_init(bsl_eidpat_numcomp_t *obj)
58{
60}
61
62void bsl_eidpat_numcomp_deinit(bsl_eidpat_numcomp_t *obj)
63{
65 {
66 bsl_eidpat_numrage_clear(obj->val.as_range);
67 }
69}
70
71void bsl_eidpat_numcomp_set_form(bsl_eidpat_numcomp_t *obj, bsl_eidpat_numcomp_form_t form)
72{
73 if (obj->form == form)
74 {
75 return;
76 }
77
79 {
80 bsl_eidpat_numrage_clear(obj->val.as_range);
81 }
82
83 obj->form = form;
84 if (form == BSL_EIDPAT_NUMCOMP_RANGE)
85 {
86 bsl_eidpat_numrage_init(obj->val.as_range);
87 }
88}
89
90static int one_uint64_from_text(uint64_t *val, const char *curs, const char **endptr)
91{
92 char *pend;
93 *val = strtoul(curs, &pend, 10);
94 if (pend == curs)
95 {
96 // failed decoding
97 return 2;
98 }
99 *endptr = pend;
100 return 0;
101}
102
103int bsl_eidpat_numcomp_from_text(bsl_eidpat_numcomp_t *obj, const char *curs, const char **endptr)
104{
105 if (*curs == '\0')
106 {
107 // no text at start
108 return 4;
109 }
110
111 if (*curs == '*')
112 {
113 // wildcard
114 bsl_eidpat_numcomp_set_form(obj, BSL_EIDPAT_NUMCOMP_WILDCARD);
115 ++curs;
116 }
117 else if (*curs == '[')
118 {
119 // range
120 bsl_eidpat_numcomp_set_form(obj, BSL_EIDPAT_NUMCOMP_RANGE);
121 ++curs;
122
123 const char *range_end = strchr(curs, ']');
124 while (curs < range_end)
125 {
127
128 const char *pend;
129 if (one_uint64_from_text(&seg.first, curs, &pend))
130 {
131 return 4;
132 }
133 curs = pend;
134
135 // determine interval or single value
136 if (*curs == '-')
137 {
138 ++curs;
139
140 if (one_uint64_from_text(&seg.last, curs, &pend))
141 {
142 return 4;
143 }
144 curs = pend;
145 }
146 else
147 {
148 // single-value segment
149 seg.last = seg.first;
150 }
151
152 // check for overlaps
153 const bsl_eidpat_numrange_seg_t *near_low = NULL, *near_high = NULL;
154 if (!bsl_eidpat_numrage_empty_p(obj->val.as_range))
155 {
156 bsl_eidpat_numrage_it_t existing;
157 bsl_eidpat_numrage_it_from(existing, obj->val.as_range, seg);
158 if (bsl_eidpat_numrage_end_p(existing))
159 {
160 near_low = bsl_eidpat_numrage_max(obj->val.as_range);
161 }
162 else
163 {
164 near_high = bsl_eidpat_numrage_cref(existing);
165 // FIXME no bsl_eidpat_numrage_prev() function to go backward
166 }
167 }
168
169 if (near_low && bsl_eidpat_numrange_seg_overlap(&seg, near_low))
170 {
171 // overlap with existing
172 return 6;
173 }
174 if (near_high && bsl_eidpat_numrange_seg_overlap(&seg, near_high))
175 {
176 // overlap with existing
177 return 6;
178 }
179 bsl_eidpat_numrage_push(obj->val.as_range, seg);
180
181 // last item has no trailing comma
182 if (*curs == ',')
183 {
184 ++curs;
185 }
186 }
187 ++curs;
188 }
189 else
190 {
191 // single value
192 bsl_eidpat_numcomp_set_form(obj, BSL_EIDPAT_NUMCOMP_SINGLE);
193 const char *pend;
194 if (one_uint64_from_text(&obj->val.as_single, curs, &pend))
195 {
196 return 4;
197 }
198 curs = pend;
199 }
200
201 *endptr = curs;
202 return 0;
203}
204
205bool bsl_eidpat_numcomp_match(const bsl_eidpat_numcomp_t *obj, uint64_t val)
206{
207 switch (obj->form)
208 {
210 // value-independent
211 return true;
213 return obj->val.as_single == val;
215 {
216 // search for singleton segment
218 .first = val,
219 .last = val,
220 };
221 bsl_eidpat_numrage_it_t it;
222 bsl_eidpat_numrage_it_from(it, obj->val.as_range, key);
223 if (bsl_eidpat_numrage_end_p(it))
224 {
225 return false;
226 }
227 const bsl_eidpat_numrange_seg_t *found = bsl_eidpat_numrage_cref(it);
228 return ((val >= found->first) && (val <= found->last));
229 }
230 }
231 return false;
232}
233
234void bsl_eidpat_ipn_ssp_init(bsl_eidpat_ipn_ssp_t *obj)
235{
236 bsl_eidpat_numcomp_init(&(obj->auth));
237 bsl_eidpat_numcomp_init(&(obj->node));
238 bsl_eidpat_numcomp_init(&(obj->svc));
239}
240
241void bsl_eidpat_ipn_ssp_deinit(bsl_eidpat_ipn_ssp_t *obj)
242{
243 bsl_eidpat_numcomp_deinit(&(obj->auth));
244 bsl_eidpat_numcomp_deinit(&(obj->node));
245 bsl_eidpat_numcomp_deinit(&(obj->svc));
246}
247
248bool bsl_eidpat_ipn_ssp_match(const bsl_eidpat_ipn_ssp_t *pat, const bsl_eid_ipn_ssp_t *val)
249{
250 return (bsl_eidpat_numcomp_match(&(pat->auth), val->auth_num)
251 && bsl_eidpat_numcomp_match(&(pat->node), val->node_num)
252 && bsl_eidpat_numcomp_match(&(pat->svc), val->svc_num));
253}
254
255int bsl_mock_eidpat_item_init(bsl_mock_eidpat_item_t *obj)
256{
257 memset(obj, 0, sizeof(bsl_mock_eidpat_item_t));
258 return 0;
259}
260
261void bsl_mock_eidpat_item_deinit(bsl_mock_eidpat_item_t *obj)
262{
263 switch (obj->scheme)
264 {
265 case BSL_MOCK_EID_IPN:
266 bsl_eidpat_ipn_ssp_deinit(&(obj->ssp.as_ipn));
267 break;
268 default:
269 break;
270 }
271 memset(obj, 0, sizeof(bsl_mock_eidpat_item_t));
272}
273
274int mock_bpa_eidpat_item_from_text(bsl_mock_eidpat_item_t *item, const char *text, const char **endptr)
275{
276 CHKERR1(item);
277 CHKERR1(text);
278 CHKERR1(endptr);
279
280 // clean up if necessary
281 bsl_mock_eidpat_item_deinit(item);
282
283 const char *curs = text;
284 const char *pend = strchr(text, ':');
285 if (pend == NULL)
286 {
287 return 2;
288 }
289 size_t scheme_len = pend - text;
290 curs = pend + 1;
291
292 if (strncasecmp(text, "ipn", scheme_len) == 0)
293 {
294 item->scheme = BSL_MOCK_EID_IPN;
295
296 if (strncmp(curs, "**", 2) == 0)
297 {
298 item->any_ssp = true;
299 curs += 2;
300 }
301 else
302 {
303 bsl_eidpat_ipn_ssp_t *ipn_ssp = &(item->ssp.as_ipn);
304 bsl_eidpat_ipn_ssp_init(ipn_ssp);
305
306 if (bsl_eidpat_numcomp_from_text(&ipn_ssp->auth, curs, &pend))
307 {
308 bsl_eidpat_ipn_ssp_deinit(ipn_ssp);
309 return 4;
310 }
311 curs = pend;
312 if (*curs != '.')
313 {
314 bsl_eidpat_ipn_ssp_deinit(ipn_ssp);
315 return 4;
316 }
317 ++curs;
318
319 if (bsl_eidpat_numcomp_from_text(&ipn_ssp->node, curs, &pend))
320 {
321 bsl_eidpat_ipn_ssp_deinit(ipn_ssp);
322 return 4;
323 }
324 curs = pend;
325 if (*curs != '.')
326 {
327 bsl_eidpat_ipn_ssp_deinit(ipn_ssp);
328 return 4;
329 }
330 ++curs;
331
332 if (bsl_eidpat_numcomp_from_text(&ipn_ssp->svc, curs, &pend))
333 {
334 bsl_eidpat_ipn_ssp_deinit(ipn_ssp);
335 return 4;
336 }
337 curs = pend;
338 }
339 }
340 else
341 {
342 // unhandled scheme
343 return 3;
344 }
345
346 *endptr = curs;
347 return 0;
348}
349
350bool mock_bpa_eidpat_item_match(const bsl_mock_eidpat_item_t *item, const bsl_mock_eid_t *eid)
351{
352 CHKERR1(item);
353 CHKERR1(eid);
354
355 if (item->scheme != eid->scheme)
356 {
357 // no possibility
358 return false;
359 }
360
361 switch (item->scheme)
362 {
363 case BSL_MOCK_EID_IPN:
364 return bsl_eidpat_ipn_ssp_match(&(item->ssp.as_ipn), &(eid->ssp.as_ipn));
365 default:
366 BSL_LOG_ERR("EID Pattern scheme %" PRIu64 " not handled", item->scheme);
367 break;
368 }
369 return false;
370}
371
372int mock_bpa_eidpat_init(BSL_HostEIDPattern_t *pat, void *user_data _U_)
373{
374 CHKERR1(pat);
375 memset(pat, 0, sizeof(BSL_HostEIDPattern_t));
376 pat->handle = BSL_MALLOC(sizeof(bsl_mock_eidpat_t));
377 if (!(pat->handle))
378 {
379 return 2;
380 }
381 {
382 memset(pat->handle, 0, sizeof(bsl_mock_eidpat_t));
383 bsl_mock_eidpat_t *obj = pat->handle;
384 bsl_mock_eidpat_item_list_init(obj->items);
385 }
386 return 0;
387}
388
389static void bsl_mock_eidpat_deinit(bsl_mock_eidpat_t *pat)
390{
391 CHKVOID(pat);
392 bsl_mock_eidpat_item_list_clear(pat->items);
393 memset(pat, 0, sizeof(bsl_mock_eidpat_t));
394}
395
396void mock_bpa_eidpat_deinit(BSL_HostEIDPattern_t *pat, void *user_data _U_)
397{
398 CHKVOID(pat);
399 if (pat->handle)
400 {
401 bsl_mock_eidpat_deinit(pat->handle);
402 BSL_FREE(pat->handle);
403 }
404 memset(pat, 0, sizeof(BSL_HostEIDPattern_t));
405}
406
407int mock_bpa_eidpat_from_text(BSL_HostEIDPattern_t *pat, const char *text, void *user_data _U_)
408{
409 CHKERR1(pat);
410 CHKERR1(text);
411 bsl_mock_eidpat_t *obj = pat->handle;
412 CHKERR1(obj);
413
414 // clean up if necessary
415 bsl_mock_eidpat_item_list_reset(obj->items);
416
417 const char *curs = text;
418 const char *end = curs + strlen(text);
419 const char *pend;
420
421 bool match_all = false;
422 if (strcmp(curs, "*:**") == 0)
423 {
424 // leave items empty and finish
425 match_all = true;
426 curs += 4;
427 }
428
429 while (curs < end)
430 {
431 bsl_mock_eidpat_item_t *item = bsl_mock_eidpat_item_list_push_back_new(obj->items);
432 if (mock_bpa_eidpat_item_from_text(item, curs, &pend))
433 {
434 bsl_mock_eidpat_item_list_reset(obj->items);
435 return 3;
436 }
437 curs = pend;
438
439 // FIXME could make more robust
440 if (*curs == '|')
441 {
442 ++curs;
443 }
444 }
445
446 if (match_all ^ bsl_mock_eidpat_item_list_empty_p(obj->items))
447 {
448 return 6;
449 }
450
451 return 0;
452}
453
454bool mock_bpa_eidpat_match(const BSL_HostEIDPattern_t *pat, const BSL_HostEID_t *eid, void *user_data _U_)
455{
456 CHKERR1(pat);
457 CHKERR1(pat->handle);
458 CHKERR1(eid);
459 CHKERR1(eid->handle);
461 bsl_mock_eid_t *eidobj = (bsl_mock_eid_t *)eid->handle;
462
463 // any-scheme condition
464 if (bsl_mock_eidpat_item_list_empty_p(patobj->items))
465 {
466 return true;
467 }
468
469 bsl_mock_eidpat_item_list_it_t it;
470 for (bsl_mock_eidpat_item_list_it(it, patobj->items); !bsl_mock_eidpat_item_list_end_p(it);
471 bsl_mock_eidpat_item_list_next(it))
472 {
473 const bsl_mock_eidpat_item_t *item = bsl_mock_eidpat_item_list_cref(it);
474 if (mock_bpa_eidpat_item_match(item, eidobj))
475 {
476 return true;
477 }
478 }
479 return false;
480}
Single entry-point include file for all of the BPSec Lib (BSL) frontend API.
#define CHKVOID(cond)
Return from void functions if condition fails.
#define _U_
Mark an unused parameter Within a function definition.
#define CHKERR1(cond)
Return the error value 1 if condition fails.
#define BSL_LOG_ERR(...)
This is an overloaded member function, provided for convenience. It differs from the above function o...
@ BSL_MOCK_EID_IPN
The "ipn" scheme.
Declarations for EID Pattern handling.
bsl_eidpat_numcomp_form_t
The component type for a numeric tuple pattern.
@ BSL_EIDPAT_NUMCOMP_RANGE
A multi-segment range of values.
@ BSL_EIDPAT_NUMCOMP_SINGLE
A single numeric value.
@ BSL_EIDPAT_NUMCOMP_WILDCARD
This form has no associated value.
Reference to a EID pattern owned and stored in the BPA.
void * handle
Opaque pointer for BPA backend to use.
Opaque pointer to BPA-specific Endpoint ID storage.
void * handle
Opaque pointer for BPA backend to use.
Scheme-specific part for IPN scheme.
uint64_t svc_num
The service number component.
uint64_t node_num
The node number component.
uint64_t auth_num
The authority number component.
Scheme-specific part for IPN scheme.
Each component of a numeric tuple pattern.
bsl_eidpat_numcomp_form_t form
The form of the component val.
bsl_eidpat_numrage_t as_range
Used for BSL_EIDPAT_NUMCOMP_RANGE.
uint64_t as_single
Used for BSL_EIDPAT_NUMCOMP_SINGLE.
union bsl_eidpat_numcomp_t::@1 val
The component value interpreted according to form.
A single numeric range segment pair.
uint64_t last
The last value in this segment, also used to sort segments.
uint64_t first
The first value in this segment.
Struct to be used as a BSL_HostEID_t::handle.
union bsl_mock_eid_t::@0 ssp
Interpreted according to scheme code.
bsl_eid_ipn_ssp_t as_ipn
Used when scheme is BSL_MOCK_EID_IPN.
uint64_t scheme
Code point for EID schemes from .
One item of an EID Pattern.
bool any_ssp
True if this is a match-any-SSP item.
union bsl_mock_eidpat_item_t::@2 ssp
Interpreted according to scheme code when any_ssp is false.
uint64_t scheme
Code point for EID schemes from .
bsl_eidpat_ipn_ssp_t as_ipn
Used when scheme is BSL_MOCK_EID_IPN.
Struct to be used as a BSL_HostEIDPattern_t::handle.
bsl_mock_eidpat_item_list_t items
The list of pattern items, or an empty list to indicate the any-scheme pattern.