BSL v0.0.0
AMMOS Bundle Protocol Security Library (BSL)
Loading...
Searching...
No Matches
BIB_HMAC_SHA2.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
29#include <qcbor/qcbor_encode.h>
30#include <qcbor/qcbor_spiffy_decode.h>
31#include <stdio.h>
32#include <sys/types.h>
33#include <time.h>
34
35#include <BPSecLib_Private.h>
36#include <CryptoInterface.h>
37
38#include "DefaultSecContext.h"
40#include "rfc9173.h"
41
42bool BSLX_BIB_Validate(BSL_LibCtx_t *lib, const BSL_BundleRef_t *bundle, const BSL_SecOper_t *sec_oper)
43{
44 // Note: Internal API distinction.
45 // Called before the `_execute` function. This checks ahead of time whether it contains the necessary info in order
46 // to perform the execution.
47 assert(0);
48 (void)lib;
49 (void)bundle;
50 (void)sec_oper;
51 return false;
52}
53
54bool BSLX_BCB_Validate(BSL_LibCtx_t *lib, const BSL_BundleRef_t *bundle, const BSL_SecOper_t *sec_oper)
55{
56 assert(0);
57 (void)lib;
58 (void)bundle;
59 (void)sec_oper;
60 return false;
61}
62
63size_t BSLX_Bytestr_GetCapacity(void)
64{
65 return BSL_DEFAULT_BYTESTR_LEN;
66}
67
68BSL_Data_t BSLX_Bytestr_AsData(BSLX_Bytestr_t *self)
69{
70 BSL_Data_t result = { .owned = false, .len = self->bytelen, .ptr = self->_bytes };
71 return result;
72}
73
78static ssize_t map_rfc9173_sha_variant_to_crypto(size_t rfc9173_sha_variant)
79{
80 ssize_t crypto_sha_variant = -1;
81 if (rfc9173_sha_variant == RFC9173_BIB_SHA_HMAC512)
82 {
83 crypto_sha_variant = BSL_CRYPTO_SHA_512;
84 }
85 else if (rfc9173_sha_variant == RFC9173_BIB_SHA_HMAC384)
86 {
87 crypto_sha_variant = BSL_CRYPTO_SHA_384;
88 }
89 else if (rfc9173_sha_variant == RFC9173_BIB_SHA_HMAC256)
90 {
91 crypto_sha_variant = BSL_CRYPTO_SHA_256;
92 }
93 else
94 {
95 BSL_LOG_ERR("Unknown RFC9173 SHA variant index: %lu", rfc9173_sha_variant);
96 crypto_sha_variant = BSL_ERR_PROPERTY_CHECK_FAILED;
97 }
98 BSL_LOG_DEBUG("Mapping RFC9173 SHA Variant %lu -> %ld", rfc9173_sha_variant, crypto_sha_variant);
99 return crypto_sha_variant;
100}
101
108{
109 assert(self != NULL);
110 assert(sec_oper != NULL);
111 memset(self, 0, sizeof(*self));
112 self->sha_variant = -1;
113 self->integrity_scope_flags = -1;
114 self->key_id = -1;
115
116 for (size_t param_index = 0; param_index < BSL_SecOper_CountParams(sec_oper); param_index++)
117 {
118 const BSL_SecParam_t *param = BSL_SecOper_GetParamAt(sec_oper, param_index);
119 uint64_t param_id = BSL_SecParam_GetId(param);
120 bool is_int = BSL_SecParam_IsInt64(param);
121 uint64_t int_val = -1;
122 if (is_int)
123 {
124 int_val = BSL_SecParam_GetAsUInt64(param);
125 }
126
127 if (param_id == BSL_SECPARAM_TYPE_INT_KEY_ID)
128 {
129 assert(is_int);
130 self->key_id = int_val;
131 }
132 else if (param_id == BSL_SECPARAM_TYPE_INT_FIXED_KEY)
133 {
134 assert(0);
135 assert(!is_int);
136 BSL_Data_t bytestr_data = BSLX_Bytestr_AsData(&self->override_key);
137 BSL_SecParam_GetAsBytestr(param, &bytestr_data);
138 self->override_key.bytelen = bytestr_data.len;
139 }
140 else if (param_id == RFC9173_BIB_PARAMID_SHA_VARIANT)
141 {
142 assert(is_int);
143 self->sha_variant = int_val;
144 }
145 else if (param_id == RFC9173_BIB_PARAMID_INTEG_SCOPE_FLAG)
146 {
147 assert(is_int);
148 self->integrity_scope_flags = int_val;
149 }
150 else if (param_id == RFC9173_BIB_PARAMID_WRAPPED_KEY)
151 {
152 assert(!is_int);
153 BSL_Data_t bytestr_data = BSLX_Bytestr_AsData(&self->wrapped_key);
154 BSL_SecParam_GetAsBytestr(param, &bytestr_data);
155 self->wrapped_key.bytelen = bytestr_data.len;
156 }
157 else
158 {
159 BSL_LOG_WARNING("Unknown param id: %lu", param_id);
161 }
162 }
163
164 if (self->sha_variant < 0)
165 {
166 // Default is SHA384: https://www.rfc-editor.org/rfc/rfc9173.html#name-block-integrity-block
167 BSL_LOG_DEBUG("No SHA Variant set, defaulting to SHA_HMAC384");
168 self->sha_variant = RFC9173_BIB_SHA_HMAC384;
169 }
170 self->sha_variant = map_rfc9173_sha_variant_to_crypto(self->sha_variant);
171 if (self->sha_variant < 0)
172 {
173 BSL_LOG_WARNING("BIB SHA varient required.");
175 }
176 if (self->integrity_scope_flags < 0)
177 {
178 // If none given, assume they must all be true per spec.
179 BSL_LOG_DEBUG("No scope flag set, defaulting to everything (0x07)");
180 self->integrity_scope_flags = 0x07;
181 }
182 return BSL_SUCCESS;
183}
184
189{
190 assert(self != NULL);
191 assert(ippt_space.len > 0);
192 assert(ippt_space.ptr != NULL);
193
194 int res = BSL_ERR_FAILURE;
195 QCBOREncodeContext encoder;
196 QCBORError cbor_err = QCBOR_ERR_UNSUPPORTED;
197 UsefulBuf result_ub = { .ptr = ippt_space.ptr, ippt_space.len };
198 QCBOREncode_Init(&encoder, result_ub);
199 QCBOREncode_AddInt64(&encoder, self->integrity_scope_flags);
200
201 if (self->target_block.block_num > 0)
202 {
203 // Now begin process of computing IPPT
204 if (self->integrity_scope_flags & RFC9173_BIB_INTEGSCOPEFLAG_INC_PRIM)
205 {
206 UsefulBufC prim_encoded = { .ptr = self->primary_block.cbor,
207 .len = self->primary_block.cbor_len };
208 QCBOREncode_AddEncoded(&encoder, prim_encoded);
209 }
210 if (self->integrity_scope_flags & RFC9173_BIB_INTEGSCOPEFLAG_INC_TARGET_HDR)
211 {
212 BSLX_EncodeHeader(&self->target_block, &encoder);
213 }
214 }
215
216 if (self->integrity_scope_flags & RFC9173_BIB_INTEGSCOPEFLAG_INC_SEC_HDR)
217 {
218 BSLX_EncodeHeader(&self->sec_block, &encoder);
219 }
220
221 const uint8_t *target_cbor = self->primary_block.cbor;
222 size_t target_cbor_len = self->primary_block.cbor_len;
223
224 if (self->target_block.block_num > 0)
225 {
226 target_cbor = self->target_block.btsd;
227 target_cbor_len = self->target_block.btsd_len;
228 }
229 UsefulBufC target_blk_btsd = { .ptr = target_cbor, .len = target_cbor_len };
230 QCBOREncode_AddBytes(&encoder, target_blk_btsd);
231 UsefulBufC ippt_result;
232 cbor_err = QCBOREncode_Finish(&encoder, &ippt_result);
233 if (cbor_err != QCBOR_SUCCESS)
234 {
235 BSL_LOG_ERR("CBOR encoding IPPT failed, code=%" PRIu32 " (%s)", cbor_err, qcbor_err_to_str(cbor_err));
236 res = BSL_ERR_ENCODING;
237 goto error;
238 }
239 return (int)(ippt_result.len);
240
241error:;
242 return res;
243}
244
252{
253 CHK_ARG_NONNULL(self);
254
255 BSL_AuthCtx_t hmac_ctx;
256
257 int res = 0;
258 if ((res = BSL_AuthCtx_Init(&hmac_ctx, self->key_id, self->sha_variant)) != 0)
259 {
260 BSL_LOG_ERR("bsl_hmac_ctx_init failed with code %d", res);
261 goto error;
262 }
263 if ((res = BSL_AuthCtx_DigestBuffer(&hmac_ctx, ippt_data.ptr, ippt_data.len)) != 0)
264 {
265 BSL_LOG_ERR("bsl_hmac_ctx_input_data_buffer failed with code %d", res);
266 goto error;
267 }
268
269 void *hmac_result_ptr = (void *)&self->hmac_result_val._bytes[0];
270 size_t hmaclen = 0;
271 if ((res = BSL_AuthCtx_Finalize(&hmac_ctx, &hmac_result_ptr, &hmaclen)) != 0)
272 {
273 BSL_LOG_ERR("bsl_hmac_ctx_finalize failed with code %d", res);
274 goto error;
275 }
276 self->hmac_result_val.bytelen = hmaclen;
277
278 if ((res = BSL_AuthCtx_Deinit(&hmac_ctx)) != 0)
279 {
280 BSL_LOG_ERR("bsl_hmac_ctx_deinit failed with code %d", res);
281 goto error;
282 }
283 assert(hmaclen > 0);
284 return (int)hmaclen;
285
286error:
287 BSL_AuthCtx_Deinit(&hmac_ctx);
288 BSL_LOG_ERR("%s failed bsl_crypto code=%ld", __func__, res);
290}
291
292int BSLX_BIB_Execute(BSL_LibCtx_t *lib, const BSL_BundleRef_t *bundle, const BSL_SecOper_t *sec_oper,
293 BSL_SecOutcome_t *sec_outcome)
294{
295 CHK_ARG_NONNULL(lib);
296 CHK_ARG_NONNULL(bundle);
297 CHK_ARG_NONNULL(sec_oper);
298 CHK_ARG_NONNULL(sec_outcome);
299
300 CHK_PRECONDITION(BSL_SecOper_IsConsistent(sec_oper));
301
302 BSL_Data_t scratch_buffer = { 0 };
303 if (BSL_SUCCESS != BSL_Data_InitBuffer(&scratch_buffer, 4096 * 4))
304 {
305 BSL_LOG_ERR("Failed to allocate scratch space");
307 }
308
309 BSLX_ScratchSpace_t scratch;
310 scratch.buffer = scratch_buffer.ptr;
311 scratch.size = scratch_buffer.len;
312 scratch.position = 1;
313
314 BSL_Data_t ippt_space = { .ptr = BSLX_ScratchSpace_take(&scratch, 5000), .len = 5000 };
315
316 BSLX_BIB_t bib_context = { 0 };
317 BSLX_BIB_InitFromSecOper(&bib_context, sec_oper);
318
319 if (BSL_SUCCESS != BSL_BundleCtx_GetBundleMetadata(bundle, &bib_context.primary_block))
320 {
321 BSL_LOG_ERR("Failed to get bundle data");
322 goto error;
323 }
324
325 const uint64_t target_blk_num = BSL_SecOper_GetTargetBlockNum(sec_oper);
326 if (target_blk_num > 0)
327 {
328 // If the target block num is 0 (the primary block), then we do not need to fetch this
329 if (BSL_SUCCESS != BSL_BundleCtx_GetBlockMetadata(bundle, target_blk_num, &bib_context.target_block))
330 {
331 BSL_LOG_ERR("Failed to get block data");
332 goto error;
333 }
334 }
335
336 const uint64_t sec_blk_num = BSL_SecOper_GetSecurityBlockNum(sec_oper);
337 if (BSL_SUCCESS != BSL_BundleCtx_GetBlockMetadata(bundle, sec_blk_num, &bib_context.sec_block))
338 {
339 // It is somewhat anomalous to fail to get the security block;
340 // It should already have been created. However, when doing set-piece
341 // tests, it is possible. And it's not always needed for the security
342 // operation anyway. So for now, long a warning about it, but otherwise proceed.
343 BSL_LOG_WARNING("Failed to get security block data");
344 }
345
346 const int ippt_len = BSLX_BIB_GenIPPT(&bib_context, ippt_space);
347 if (ippt_len <= 0)
348 {
349 BSL_LOG_ERR("GenIPPT returned %d", ippt_len);
350 goto error;
351 }
352 assert(ippt_len > 0);
353 ippt_space.len = (size_t)ippt_len;
354
355 const int hmac_nbytes = BSLX_BIB_GenHMAC(&bib_context, ippt_space);
356 if (hmac_nbytes < BSL_SUCCESS)
357 {
358 BSL_LOG_ERR("Failed to generate BIB HMAC");
359 goto error;
360 }
361
362 // This gets all the parameters that need to be placed in the output
363 for (size_t index = 0; index < BSL_SecOper_CountParams(sec_oper); index++)
364 {
365 const BSL_SecParam_t *sec_param = BSL_SecOper_GetParamAt(sec_oper, index);
367 {
369 memcpy(dst_param, sec_param, BSL_SecParam_Sizeof());
370 BSL_SecOutcome_AppendParam(sec_outcome, dst_param);
371 }
372 }
373
375 BSL_SecResult_Init(bib_result, RFC9173_BIB_RESULTID_HMAC, RFC9173_CONTEXTID_BIB_HMAC_SHA2,
376 BSL_SecOper_GetTargetBlockNum(sec_oper), BSLX_Bytestr_AsData(&bib_context.hmac_result_val));
377 BSL_SecOutcome_AppendResult(sec_outcome, bib_result);
378
379 BSL_Data_Deinit(&scratch_buffer);
380 return BSL_SUCCESS;
381
382error:
383
384 BSL_Data_Deinit(&scratch_buffer);
386}
int BSLX_BIB_InitFromSecOper(BSLX_BIB_t *self, const BSL_SecOper_t *sec_oper)
Populate the BIB parameters convenience struct from the security operation struct.
int BSLX_BIB_GenHMAC(BSLX_BIB_t *self, BSL_Data_t ippt_data)
Performs the actual HMAC over the given IPPT, placing the result in hmac_result.
int BSLX_BIB_GenIPPT(BSLX_BIB_t *self, BSL_Data_t ippt_space)
Computes the Integrity-Protected Plaintext (IPPT) for a canonical bundle block (non-primary)
static ssize_t map_rfc9173_sha_variant_to_crypto(size_t rfc9173_sha_variant)
Provides the mapping from the security-context-specific ID defined in RFC9173 to the local ID of the ...
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_SECPARAM_TYPE_INT_KEY_ID
Used to pass in a key id found in the key registry.
@ BSL_SECPARAM_TYPE_INT_FIXED_KEY
Used by tests to pass in a specific key bytestring.
#define BSL_LOG_WARNING(...)
This is an overloaded member function, provided for convenience. It differs from the above function o...
#define BSL_LOG_ERR(...)
This is an overloaded member function, provided for convenience. It differs from the above function o...
@ BSL_ERR_PROPERTY_CHECK_FAILED
The BSL of a structure within it is not in a valid state.
@ BSL_ERR_ENCODING
CBOR encoding failure.
@ BSL_ERR_SECURITY_CONTEXT_FAILED
Security Context errors start at 200.
@ BSL_ERR_INSUFFICIENT_SPACE
Insufficient space to complete.
@ BSL_ERR_SECURITY_OPERATION_FAILED
Security operation failed (e.g., BIB did not have enough parameters)
@ BSL_SUCCESS
Placeholder for non-error code.
@ BSL_ERR_FAILURE
Uncategorized failed (prefer to avoid)
int BSL_AuthCtx_Finalize(BSL_AuthCtx_t *hmac_ctx, void **hmac, size_t *hmac_len)
Finalize HMAC tag.
int BSL_AuthCtx_Init(BSL_AuthCtx_t *hmac_ctx, uint64_t keyid, BSL_CryptoCipherSHAVariant_e sha_var)
Initialize HMAC context resources and set private key and SHA variant.
int BSL_AuthCtx_DigestBuffer(BSL_AuthCtx_t *hmac_ctx, const void *data, size_t data_len)
Input data to HMAC sign to context.
int BSL_AuthCtx_Deinit(BSL_AuthCtx_t *hmac_ctx)
Deinitialize HMAC context resources.
Abstract interface for crypto processing.
void * BSLX_ScratchSpace_take(BSLX_ScratchSpace_t *scratch, size_t len)
This means "give me len bytes from the scratch space and increment a counter." This is a convenience ...
Header for the implementation of an example default security context (RFC 9173).
Contains functions only used internally, however, test utilities can include this to unit test them.
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.
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.
uint64_t BSL_SecOper_GetSecurityBlockNum(const BSL_SecOper_t *self)
Get the block number of the security block containing this sec operation.
uint64_t BSL_SecOper_GetTargetBlockNum(const BSL_SecOper_t *self)
Get the block number of the target block covered by this security operation.
size_t BSL_SecOper_CountParams(const BSL_SecOper_t *self)
Get the count of parameters contained within this security operation.
const BSL_SecParam_t * BSL_SecOper_GetParamAt(const BSL_SecOper_t *self, size_t index)
Returns a pointer to the Security Parameter at a given index in the list of all paramters.
bool BSL_SecOper_IsConsistent(const BSL_SecOper_t *self)
Returns true if internal consistency and sanity checks pass.
int BSL_SecParam_IsInt64(const BSL_SecParam_t *self)
Returns true when the value type is an integer.
Definition SecParam.c:63
int BSL_SecParam_GetAsBytestr(const BSL_SecParam_t *self, BSL_Data_t *result)
Retrieve bytestring value of result when security parameter type is bytestring.
Definition SecParam.c:77
uint64_t BSL_SecParam_GetId(const BSL_SecParam_t *self)
Get parameter ID of this param.
Definition SecParam.c:85
size_t BSL_SecParam_Sizeof(void)
Return size of BSL_SecParam_t struct type.
Definition SecParam.c:29
bool BSL_SecParam_IsParamIDOutput(uint64_t param_id)
Indicates true when this parameter is NOT an implementation-specific security paramter.
Definition SecParam.c:111
uint64_t BSL_SecParam_GetAsUInt64(const BSL_SecParam_t *self)
Retrieve integer value of result when this result type is integer.
Definition SecParam.c:69
int BSL_SecResult_Init(BSL_SecResult_t *self, uint64_t result_id, uint64_t context_id, uint64_t target_block_num, BSL_Data_t content)
Populate a pre-allocated SecResult.
Definition SecResult.c:28
size_t BSL_SecResult_Sizeof(void)
Returns size in bytes of BSL_SecResult_t.
Definition SecResult.c:59
int BSL_Data_Deinit(BSL_Data_t *data)
De-initialize a data struct, freeing if necessary.
int BSL_Data_InitBuffer(BSL_Data_t *data, size_t bytelen)
Initialize with an owned buffer of size bytelen.
Contains constants as defined in IETF RFC 9173 (Default Security Context for BPSec)
Wrapper for large, variable-sized buffer holding all working data to compete a BCB operation.
Struct def for HMAC operation context.
Reference to a Bundle owned and stored in the host BPA.
uint64_t block_num
CBOR-decoded block number (should always be > 0)
void * btsd
Pointer to BTSD owned by the host BPA.
size_t btsd_len
Length in bytes of the BTSD pointer.
Heap data storage and views.
size_t len
Size of the data buffer.
BSL_DataPtr_t ptr
Pointer to the front of the buffer.
bool owned
True if this data is a copy.
Concrete definition of library context.