BSL v0.0.0
AMMOS Bundle Protocol Security Library (BSL)
Loading...
Searching...
No Matches
SamplePolicyProvider.c
Go to the documentation of this file.
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
28#include <stddef.h>
29#include <stdlib.h>
30
31#include <BPSecLib_Private.h>
32#include <sys/types.h>
33
35
36static bool BSLP_PolicyProvider_IsConsistent(const BSLP_PolicyProvider_t *self)
37{
38 assert(self != NULL);
39 assert(strlen(self->name) < sizeof(self->name)); // TODO - Safer strlen since no strnlen
40 assert(self->rule_count < (sizeof(self->rules) / sizeof(BSLP_PolicyRule_t)));
41 return true;
42}
43
44static bool BSLP_PolicyPredicate_IsConsistent(const BSLP_PolicyPredicate_t *self)
45{
46 assert(self != NULL);
47 assert(self->location > 0);
48 assert(self->dst_eid_pattern.handle != NULL);
49 assert(self->src_eid_pattern.handle != NULL);
50 assert(self->secsrc_eid_pattern.handle != NULL);
51 return true;
52}
53
54static bool BSLP_PolicyRule_IsConsistent(const BSLP_PolicyRule_t *self)
55{
56 assert(self != NULL);
57 assert(strlen(self->description) < sizeof(self->description));
58 assert(self->params != NULL);
59 assert(BSL_SECROLE_ISVALID(self->role));
60 assert(self->sec_block_type > 0);
61 assert(self->context_id > 0);
62 // NOLINTBEGIN
63 assert(BSLP_PolicyPredicate_IsConsistent(self->predicate));
64 // NOLINTEND
65 return true;
66}
67
68static uint64_t get_target_block_id(const BSL_BundleRef_t *bundle, uint64_t target_block_type)
69{
70 uint64_t target_block_num = 0;
71 for (uint64_t block_index = 1; block_index < 100; block_index++)
72 {
73 BSL_CanonicalBlock_t test_block = { 0 };
74 if (BSL_SUCCESS == BSL_BundleCtx_GetBlockMetadata(bundle, block_index, &test_block))
75 {
76 if (test_block.type_code == target_block_type)
77 {
78 target_block_num = block_index;
79 break;
80 }
81 }
82 }
83 // Returns zero if target block type not found.
84 return target_block_num;
85}
86
90int BSLP_QueryPolicy(const void *user_data, BSL_SecurityActionSet_t *output_action_set, const BSL_BundleRef_t *bundle,
91 BSL_PolicyLocation_e location)
92{
93 // This is an output struct. The caller only provides the allocation for it (which must be zero)
94 const BSLP_PolicyProvider_t *self = user_data;
95 assert(BSLP_PolicyProvider_IsConsistent(self));
96
97 BSL_PrimaryBlock_t primary_block = { 0 };
98 if (BSL_SUCCESS != BSL_BundleCtx_GetBundleMetadata(bundle, &primary_block))
99 {
100 BSL_LOG_ERR("Failed to retrieve primary block");
102 }
103
104 BSL_SecurityActionSet_Init(output_action_set);
105 const size_t capacity = sizeof(self->rules) / sizeof(BSLP_PolicyRule_t);
106
107 for (size_t index = 0; index < self->rule_count && index < capacity; index++)
108 {
109 const BSLP_PolicyRule_t *rule = &self->rules[index];
110 CHK_PROPERTY(BSLP_PolicyRule_IsConsistent(rule));
111 BSL_LOG_DEBUG("Evaluating against rule `%s`", rule->description);
112
113 if (!BSLP_PolicyPredicate_IsMatch(rule->predicate, location, primary_block.field_src_node_id,
114 primary_block.field_dest_eid))
115 {
116 BSL_LOG_DEBUG("Rule `%s` not a match", rule->description);
117 continue;
118 }
119
120 uint64_t target_block_num = get_target_block_id(bundle, rule->target_block_type);
121 if (target_block_num == 0 && rule->target_block_type != BSL_BLOCK_TYPE_PRIMARY)
122 {
123 BSL_LOG_WARNING("Cannot find target block type = %lu", rule->target_block_type);
124 BSL_SecurityActionSet_IncrError(output_action_set);
125 continue;
126 }
127
128 BSL_SecOper_t *sec_oper = calloc(BSL_SecurityActionSet_Sizeof(), 1);
129 if (BSLP_PolicyRule_EvaluateAsSecOper(rule, sec_oper, bundle, location) < 0)
130 {
131 BSL_SecurityActionSet_IncrError(output_action_set);
132 }
133 else
134 {
135 BSL_SecurityActionSet_AppendSecOper(output_action_set, sec_oper);
136 }
137 free(sec_oper);
138 BSL_LOG_INFO("Created sec operation for rule `%s`", rule->description);
139 }
140
141 CHK_POSTCONDITION(BSL_SecurityActionSet_IsConsistent(output_action_set));
142 return (int)BSL_SecurityActionSet_CountErrors(output_action_set);
143}
144
145void BSLP_PolicyPredicate_Deinit(BSLP_PolicyPredicate_t *self)
146{
147 BSL_HostEIDPattern_Deinit(&self->dst_eid_pattern);
148 BSL_HostEIDPattern_Deinit(&self->secsrc_eid_pattern);
149 BSL_HostEIDPattern_Deinit(&self->src_eid_pattern);
150 memset(self, 0, sizeof(*self));
151}
152
153void BSLP_Deinit(void *user_data)
154{
155 BSLP_PolicyProvider_t *self = user_data;
156 assert(BSLP_PolicyProvider_IsConsistent(self));
157 for (size_t index = 0; index < self->rule_count; index++)
158 {
159 BSL_LOG_INFO("Sample Policy Provider deinit rule index %lu", index);
160 BSLP_PolicyRule_Deinit(&self->rules[index]);
161 }
162
163 for (size_t index = 0; index < self->predicate_count; index++)
164 {
165 BSLP_PolicyPredicate_Deinit(&self->predicates[index]);
166 }
167 memset(self, 0, sizeof(*self));
168}
169
171 BSL_HostEIDPattern_t src_eid_pattern, BSL_HostEIDPattern_t secsrc_eid_pattern,
172 BSL_HostEIDPattern_t dst_eid_pattern)
173{
174 // todo - eid patterns should be pointers since they are non-trivial copyable.
175 assert(self != NULL);
176 memset(self, 0, sizeof(*self));
177
178 self->location = location;
179 self->src_eid_pattern = src_eid_pattern;
180 self->secsrc_eid_pattern = secsrc_eid_pattern;
181 self->dst_eid_pattern = dst_eid_pattern;
182
183 assert(BSLP_PolicyPredicate_IsConsistent(self));
184}
185
187 BSL_HostEID_t src_eid, BSL_HostEID_t dst_eid)
188{
189 assert(BSLP_PolicyPredicate_IsConsistent(self));
190
191 bool is_location_match = location == self->location;
192 bool is_src_pattern_match = BSL_HostEIDPattern_IsMatch(&self->src_eid_pattern, &src_eid);
193 bool is_dst_pattern_match = BSL_HostEIDPattern_IsMatch(&self->dst_eid_pattern, &dst_eid);
194
195 BSL_LOG_DEBUG("Match: location=%d, src_pattern=%d, dst_pattern=%d", is_location_match, is_src_pattern_match,
196 is_dst_pattern_match);
197
198 return is_location_match && is_src_pattern_match && is_dst_pattern_match;
199}
200
201/*
202Example Rules:
203 - Template: "If Bundle src/dst match PREDICATE, then (ADD|REMOVE|VALIDATE) SEC_BLOCK_TYPE using PARAM-KEY-VALUES"
204 - "At ingress from the convergence layer, Bundles matching *.* must have a single BIB covering the primary and payload
205block using key 9" Step 1: Match the Bundle struct with all Rule structs to find a Rule that matches. If no match,
206reject
207 - Things to match on:
208 - Bitmask/something for HAS_BIB_ON_PRIMARY, HAS_BIB_ON_PAYLOAD, submasks for BIB_COVERS_PRIMARY, BIB_COVERS_TARGET
209 Step 2: Populate security parameters unique to bundle and src/dst pair.
210*/
211int BSLP_PolicyRule_Init(BSLP_PolicyRule_t *self, const char *desc, BSLP_PolicyPredicate_t *predicate,
212 uint64_t context_id, BSL_SecRole_e role, BSL_SecBlockType_e sec_block_type,
213 BSL_BundleBlockTypeCode_e target_block_type, BSL_PolicyAction_e failure_action_code)
214{
215 assert(self != NULL);
216 memset(self, 0, sizeof(*self));
217 strncpy(self->description, desc, sizeof(self->description) - 1);
218 self->sec_block_type = sec_block_type;
219 self->target_block_type = target_block_type;
220 self->predicate = predicate;
221 self->context_id = context_id;
222 // TODO(bvb) assert Role in expected range
223 self->failure_action_code = failure_action_code;
224 self->role = role;
225 self->params = calloc(BSL_SecParam_Sizeof() * 10, 1);
226 self->nparams = 0;
227 assert(BSLP_PolicyRule_IsConsistent(self));
228 return BSL_SUCCESS;
229}
230
232{
233 assert(BSLP_PolicyRule_IsConsistent(self));
234 BSL_LOG_INFO("BSLP_PolicyRule_Deinit: %s, nparams=%lu", self->description, self->nparams);
235 free(self->params);
236 memset(self, 0, sizeof(*self));
237}
238
240{
241 assert(BSL_SecParam_IsConsistent(param));
242 assert(BSLP_PolicyRule_IsConsistent(self));
243
244 // TODO(bvb) - BOUNDS CHECKING
245 assert(self->nparams < 10);
246
247 size_t offset = self->nparams * BSL_SecParam_Sizeof();
248 memcpy(&((uint8_t *)self->params)[offset], param, BSL_SecParam_Sizeof());
249 self->nparams++;
250
251 assert(BSLP_PolicyRule_IsConsistent(self));
252}
253
255 const BSL_BundleRef_t *bundle, BSL_PolicyLocation_e location)
256{
257 CHK_ARG_NONNULL(sec_oper);
258 CHK_ARG_NONNULL(bundle);
259 CHK_PRECONDITION(BSLP_PolicyRule_IsConsistent(self));
260
261 {
262 // Confirm that the rule matches the bundle.
263 BSL_PrimaryBlock_t primary_block = { 0 };
264 BSL_BundleCtx_GetBundleMetadata(bundle, &primary_block);
265 CHK_PRECONDITION(BSLP_PolicyPredicate_IsMatch(self->predicate, location, primary_block.field_src_node_id,
266 primary_block.field_dest_eid));
267 }
268
269 // The rule gives us the target block TYPE, now we have to find the ID of the block with that type.
270 uint64_t target_block_num = get_target_block_id(bundle, self->target_block_type);
271 if (target_block_num == 0 && self->target_block_type != BSL_BLOCK_TYPE_PRIMARY)
272 {
273 BSL_LOG_WARNING("Cannot find target block type = %lu", self->target_block_type);
275 }
276
277 // It's found, so initialize the security operation from the rule and bundle.
278 BSL_SecOper_Init(sec_oper, self->context_id, target_block_num, 0, self->sec_block_type, self->role,
279 self->failure_action_code);
280
281 // Next, append all the parameters from the matched rule.
282 for (size_t index = 0; index < self->nparams; index++)
283 {
284 // We need to do this weird offsetting bc it does not know the size of SecParam_t
285 size_t offset = BSL_SecParam_Sizeof() * index;
286 uint8_t *ptr = &((uint8_t *)(self->params))[offset];
287 BSL_SecOper_AppendParam(sec_oper, (BSL_SecParam_t *)ptr);
288 }
289 BSL_LOG_INFO("Created sec operation for rule `%s`", self->description);
290
291 return BSL_SUCCESS;
292}
Single entry-point include file for all of the BPSec Lib (BSL) frontend API.
#define BSL_LOG_DEBUG(...)
This is an overloaded member function, provided for convenience. It differs from the above function o...
BSL_SecBlockType_e
RFC 9172-specified block type codes for BIB and BCB.
BSL_BundleBlockTypeCode_e
Block types using IANA-assigned code points from .
@ BSL_BLOCK_TYPE_PRIMARY
Primary block ID (a special case)
BSL_PolicyAction_e
Codes indicating the fate of a block if a security operation over it fails.
#define BSL_LOG_INFO(...)
This is an overloaded member function, provided for convenience. It differs from the above function o...
#define BSL_LOG_WARNING(...)
This is an overloaded member function, provided for convenience. It differs from the above function o...
BSL_SecRole_e
Security role of an operation.
#define BSL_LOG_ERR(...)
This is an overloaded member function, provided for convenience. It differs from the above function o...
@ BSL_ERR_SECURITY_CONTEXT_FAILED
Security Context errors start at 200.
@ BSL_SUCCESS
Placeholder for non-error code.
@ BSL_ERR_HOST_CALLBACK_FAILED
Callback to the host BPA returned a non-zero code.
BSL_PolicyLocation_e
Indicates where in the lifecycle of the BPA the bundle is querying for security policy.
int BSL_BundleCtx_GetBlockMetadata(const BSL_BundleRef_t *bundle, uint64_t block_num, BSL_CanonicalBlock_t *result_block)
Returns information about the bundle Canonical block.
bool BSL_HostEIDPattern_IsMatch(const BSL_HostEIDPattern_t *pat, const BSL_HostEID_t *eid)
Determine if an EID Pattern matches a specific EID.
void BSL_HostEIDPattern_Deinit(BSL_HostEIDPattern_t *pat)
De-initialize an abstract EID Pattern.
int BSL_BundleCtx_GetBundleMetadata(const BSL_BundleRef_t *bundle, BSL_PrimaryBlock_t *result_primary_block)
Calls the host interface to get a bundle primary block information.abort.
int BSLP_PolicyRule_EvaluateAsSecOper(const BSLP_PolicyRule_t *self, BSL_SecOper_t *sec_oper, const BSL_BundleRef_t *bundle, BSL_PolicyLocation_e location)
Critical function creating a security operation from a bundle and location.
int BSLP_PolicyRule_Init(BSLP_PolicyRule_t *self, const char *desc, BSLP_PolicyPredicate_t *predicate, uint64_t context_id, BSL_SecRole_e role, BSL_SecBlockType_e sec_block_type, BSL_BundleBlockTypeCode_e target_block_type, BSL_PolicyAction_e failure_action_code)
Initialize this policy rule.
bool BSLP_PolicyPredicate_IsMatch(const BSLP_PolicyPredicate_t *self, BSL_PolicyLocation_e location, BSL_HostEID_t src_eid, BSL_HostEID_t dst_eid)
Returns true if the given predicate matches the arguments.
void BSLP_PolicyRule_AddParam(BSLP_PolicyRule_t *self, const BSL_SecParam_t *param)
Include a BPSec parameter to this rule.
void BSLP_PolicyPredicate_Init(BSLP_PolicyPredicate_t *self, BSL_PolicyLocation_e location, BSL_HostEIDPattern_t src_eid_pattern, BSL_HostEIDPattern_t secsrc_eid_pattern, BSL_HostEIDPattern_t dst_eid_pattern)
Initialize this policy predicate.
int BSLP_QueryPolicy(const void *user_data, BSL_SecurityActionSet_t *output_action_set, const BSL_BundleRef_t *bundle, BSL_PolicyLocation_e location)
Note that criticality is HIGH.
void BSLP_PolicyRule_Deinit(BSLP_PolicyRule_t *self)
De-initialize, release any resources, and zero this struct.
Spec of locally-defined data structures.
void BSL_SecOper_Init(BSL_SecOper_t *self, uint64_t context_id, uint64_t target_block_num, uint64_t sec_block_num, BSL_SecBlockType_e sec_type, BSL_SecRole_e sec_role, BSL_PolicyAction_e failure_code)
Populate a pre-allocated Security Operation with the given values.
void BSL_SecOper_AppendParam(BSL_SecOper_t *self, const BSL_SecParam_t *param)
Add the given security parameter to this list of parameters.
size_t BSL_SecParam_Sizeof(void)
Return size of BSL_SecParam_t struct type.
Definition SecParam.c:29
bool BSL_SecParam_IsConsistent(const BSL_SecParam_t *self)
Return true if invariant conditions pass.
Definition SecParam.c:92
int BSL_SecurityActionSet_AppendSecOper(BSL_SecurityActionSet_t *self, const BSL_SecOper_t *sec_oper)
Append a security operation to the security action set.
size_t BSL_SecurityActionSet_Sizeof(void)
Returns size of the struct, helpful for dynamic allocation.
bool BSL_SecurityActionSet_IsConsistent(const BSL_SecurityActionSet_t *self)
Return true if internal sanity and consistency checks pass.
void BSL_SecurityActionSet_IncrError(BSL_SecurityActionSet_t *self)
Increment a security failure for this action set.
size_t BSL_SecurityActionSet_CountErrors(const BSL_SecurityActionSet_t *self)
Returns count of failures after processing this action set.
void BSL_SecurityActionSet_Init(BSL_SecurityActionSet_t *self)
Initialize a new security action set.
THE key function that matches a bundle against a rule to provide the output action and specific param...
Concrete definition of the BSL_PolicyProvider_t.
Represents a policy rule.
Reference to a Bundle owned and stored in the host BPA.
Structure containing parsed Canonical Block fields.
uint64_t type_code
CBOR-decoded block type code (should be > 0)
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.
Contains Bundle Primary Block fields and metadata.
BSL_HostEID_t field_src_node_id
Source in host BPA's internal representation of an EID.
BSL_HostEID_t field_dest_eid
Destination in host BPA's internal representation of an EID.
Contains the populated security operations for this bundle.