BSL v0.0.0
AMMOS Bundle Protocol Security Library (BSL)
Loading...
Searching...
No Matches
BCB_AES_GCM.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 <stdlib.h>
29
30#include <qcbor/qcbor_encode.h>
31#include <qcbor/qcbor_spiffy_decode.h>
32
33#include <BPSecLib_Private.h>
34#include <CryptoInterface.h>
35
36#include "DefaultSecContext.h"
38#include "rfc9173.h"
39
40int BSLX_BCB_ComputeAAD(BSLX_BCB_t *bcb_context)
41{
42 CHK_ARG_NONNULL(bcb_context);
43
44 // AAD buffer should be unallocated (this function allocates it)
45 CHK_PRECONDITION(bcb_context->aad.len == 0);
46 CHK_PRECONDITION(bcb_context->aad.ptr == NULL);
47
48 uint64_t flags = 0;
49 flags |= ((!bcb_context->skip_aad_prim_block) & 0x01);
50 flags |= ((!bcb_context->skip_aad_target_block & 0x01) << 1);
51 flags |= ((!bcb_context->skip_aad_sec_block & 0x01) << 2);
52
53 // There are 4 fields in a block header: id, type, flags, crc
54 // See: https://www.rfc-editor.org/rfc/rfc9173.html#name-aad-scope-flags
55 // Note, this over-allocates and is resized downward later.
56 const size_t aad_len = 1024;
57 if (BSL_SUCCESS != BSL_Data_InitBuffer(&bcb_context->aad, aad_len))
58 {
59 BSL_LOG_ERR("Failed to allocate AAD space");
61 }
62
63 QCBOREncodeContext aad_enc;
64 QCBOREncode_Init(&aad_enc, (UsefulBuf) { .ptr = bcb_context->aad.ptr, .len = bcb_context->aad.len });
65 QCBOREncode_AddUInt64(&aad_enc, flags);
66
67 if (flags & 0x01UL)
68 {
69 BSL_LOG_DEBUG("Adding primary block to AAD");
70 UsefulBufC prim_blk_encoded = { .ptr = bcb_context->primary_block.cbor,
71 .len = bcb_context->primary_block.cbor_len };
72 QCBOREncode_AddEncoded(&aad_enc, prim_blk_encoded);
73 }
74 if (flags & 0x02UL)
75 {
76 BSL_LOG_DEBUG("Adding target block header to AAD");
77 BSLX_EncodeHeader(&bcb_context->target_block, &aad_enc);
78 }
79 if (flags & 0x04UL)
80 {
81 BSL_LOG_DEBUG("Adding security block header to AAD");
82 BSLX_EncodeHeader(&bcb_context->sec_block, &aad_enc);
83 }
84
85 UsefulBufC cbor_encoded_buffer = { 0 };
86 if (QCBOR_SUCCESS != QCBOREncode_Finish(&aad_enc, &cbor_encoded_buffer))
87 {
88 BSL_LOG_ERR("Failed to encode AAD in BCB");
89 BSL_Data_Deinit(&bcb_context->aad);
90 return BSL_ERR_ENCODING;
91 }
92
93 BSL_Data_Resize(&bcb_context->aad, cbor_encoded_buffer.len);
94 return BSL_SUCCESS;
95}
96
97static int BSLX_BCB_Decrypt(BSLX_BCB_t *bcb_context)
98{
99 CHK_ARG_NONNULL(bcb_context);
100
101 BSL_LOG_INFO("BCB attempting to decrypt");
102
103 // AAD must already be populated
104 CHK_PRECONDITION(bcb_context->aad.ptr != NULL);
105 CHK_PRECONDITION(bcb_context->aad.len > 0);
106
107 // Key must have been set (this feeds the key encryption key)
108 CHK_PRECONDITION(bcb_context->key_id > 0);
109
110 // BTSD replacement is not yet allocated
111 CHK_PRECONDITION(bcb_context->btsd_replacement.ptr != NULL);
112 CHK_PRECONDITION(bcb_context->btsd_replacement.len > 0);
113
114 // Must have an auth tag for us to verify
115 CHK_PRECONDITION(bcb_context->authtag.ptr != NULL);
116 CHK_PRECONDITION(bcb_context->authtag.len > 0);
117
118 // Init Vector must come in from the block params
119 CHK_PRECONDITION(bcb_context->iv.ptr != NULL);
120 CHK_PRECONDITION(bcb_context->iv.len > 0);
121
122 // Wrapped key must come in from the params
123 // CHK_PRECONDITION(bcb_context->wrapped_key.ptr != NULL);
124 // CHK_PRECONDITION(bcb_context->wrapped_key.len > 0);
125
126 bool is_aes128 = bcb_context->aes_variant == RFC9173_BCB_AES_VARIANT_A128GCM;
127 BSL_CryptoCipherAESVariant_e aes_mode = is_aes128 ? BSL_CRYPTO_AES_128 : BSL_CRYPTO_AES_256;
128
129 // Over-allocate space for Content Enc Key
130 BSL_Data_t content_enc_key = { 0 };
131 if (bcb_context->wrapped_key.len > 0)
132 {
133 BSL_Data_InitBuffer(&content_enc_key, BSLX_MAX_KEYLEN);
134 int unwrap_result =
135 BSL_Crypto_UnwrapKey(&content_enc_key, bcb_context->wrapped_key, bcb_context->key_id, aes_mode);
136 if (BSL_SUCCESS != unwrap_result)
137 {
138 BSL_LOG_ERR("Failed to unwrap AES key");
139 goto error;
140 }
141 }
142 else
143 {
144 BSL_LOG_WARNING("Using bare key without AES keywrap");
145 if (BSL_SUCCESS
146 != BSLB_Crypto_GetRegistryKey(bcb_context->key_id, (const uint8_t **)&content_enc_key.ptr,
147 &content_enc_key.len))
148 {
149 BSL_LOG_ERR("Failed to load key");
150 goto error;
151 }
152 }
153
154 // This should have resized the buffer downward
155 CHK_PROPERTY(content_enc_key.len < 2048);
156
157 BSL_Cipher_t cipher = { 0 };
158 int cipher_init = BSL_Cipher_Init(&cipher, BSL_CRYPTO_DECRYPT, aes_mode, bcb_context->iv.ptr, (int)bcb_context->iv.len,
159 content_enc_key);
160 if (BSL_SUCCESS != cipher_init)
161 {
162 BSL_LOG_ERR("Failed to init BCB AES cipher");
163 goto error;
164 }
165
166 if (BSL_SUCCESS != BSL_Cipher_AddAAD(&cipher, bcb_context->aad.ptr, bcb_context->aad.len))
167 {
168 BSL_LOG_ERR("Failed to add AAD");
169 goto error;
170 }
171
172 BSL_Data_t plaintext_data = { 0 };
173 BSL_Data_InitView(&plaintext_data, bcb_context->target_block.btsd_len, bcb_context->target_block.btsd);
174 int nbytes = BSL_Cipher_AddData(&cipher, plaintext_data, bcb_context->btsd_replacement);
175 if (nbytes < 0)
176 {
177 BSL_LOG_ERR("Decrypting BTSD ciphertext failed");
178 goto error;
179 }
180 const size_t plaintext_len = (size_t)nbytes;
181
182 // Last step is to compute the authentication tag, with is produced
183 // as an output parameter to this cipher suite.
184 if (BSL_SUCCESS != BSL_Cipher_SetTag(&cipher, bcb_context->authtag.ptr))
185 {
186 BSL_LOG_ERR("Failed to set auth tag");
187 goto error;
188 }
189
190 uint8_t aes_extra[BSLX_MAX_AES_PAD];
191 memset(aes_extra, 0, sizeof(aes_extra));
192 BSL_Data_t remainder_data = { 0 };
193 BSL_Data_InitView(&remainder_data, sizeof(aes_extra), aes_extra);
194 int finalize_bytes = BSL_Cipher_FinalizeData(&cipher, &remainder_data);
195 if (finalize_bytes < 0)
196 {
197 BSL_LOG_ERR("Failed to check auth tag");
198 goto error;
199 }
200 const size_t extra_bytes = (size_t)finalize_bytes;
201 assert(extra_bytes == 0);
202 BSL_Data_Resize(&bcb_context->btsd_replacement, plaintext_len + extra_bytes);
203
204 BSL_Data_Deinit(&bcb_context->authtag);
205 BSL_Data_Deinit(&content_enc_key);
206 BSL_Cipher_Deinit(&cipher);
207 assert(bcb_context->authtag.len == 0);
208 return BSL_SUCCESS;
209
210error:
211 BSL_Data_Deinit(&bcb_context->authtag);
212 BSL_Data_Deinit(&content_enc_key);
213 BSL_Cipher_Deinit(&cipher);
214 BSL_LOG_ERR("Returning failure from BCB decrypt");
216}
217
218int BSLX_BCB_Encrypt(BSLX_BCB_t *bcb_context)
219{
220 CHK_ARG_NONNULL(bcb_context);
221
222 // AAD must already be populated
223 CHK_PRECONDITION(bcb_context->aad.ptr != NULL);
224 CHK_PRECONDITION(bcb_context->aad.len > 0);
225
226 // Must have a key ID from the security operation parameters
227 CHK_PRECONDITION(bcb_context->key_id > 0);
228
229 // BTSD replacement is not yet allocated
230 CHK_PRECONDITION(bcb_context->btsd_replacement.ptr != NULL);
231 CHK_PRECONDITION(bcb_context->btsd_replacement.len > 0);
232
233 // Auth tag must be empty
234 CHK_PRECONDITION(bcb_context->authtag.len == 0);
235
236 bool is_aes128 = bcb_context->aes_variant == RFC9173_BCB_AES_VARIANT_A128GCM;
237 BSL_CryptoCipherAESVariant_e aes_mode = is_aes128 ? BSL_CRYPTO_AES_128 : BSL_CRYPTO_AES_256;
238
239 // The IV is already defined if being populated from a test
240 // Normally, this won't be the case, so we check here.
241 // If it is empty, then generate a random IV.
242 if (bcb_context->iv.len == 0)
243 {
244 // https://www.rfc-editor.org/rfc/rfc9173.html#name-initialization-vector-iv
245 // "A value of 12 bytes SHOULD be used unless local security policy requires a different length"
246 BSL_Data_InitBuffer(&bcb_context->iv, RFC9173_BCB_DEFAULT_IV_LEN);
247 void *iv_ptr = bcb_context->iv.ptr;
248 const size_t iv_len = bcb_context->iv.len;
249 if (BSL_SUCCESS != BSL_Crypto_GenIV(iv_ptr, iv_len))
250 {
251 BSL_LOG_ERR("Failed to generate IV");
253 }
254 }
255 else
256 {
257 BSL_LOG_WARNING("Using test-harness IV");
258 }
259
260 BSL_Data_t content_enc_key = { 0 };
261 if (BSL_SUCCESS != BSL_Data_InitBuffer(&content_enc_key, BSLX_MAX_KEYLEN))
262 {
263 BSL_LOG_ERR("Cannot allocate space for key");
264 goto error;
265 }
266
267 // Generated the CEK, using keywrap when needed
268 if (bcb_context->skip_keywrap)
269 {
270 // Bypass, use the Key-Encryption-Key (KEK) as the Content-Encryption-Key (CEK)
271 // This is legal per the RFC9173 spec, but not generally advised.
272 BSL_LOG_WARNING("Skipping keywrap (this is not advised)");
273 // Directly load key_id into content enc key
274 if (BSL_SUCCESS
275 != BSLB_Crypto_GetRegistryKey(bcb_context->key_id, (const uint8_t **)&content_enc_key.ptr,
276 &content_enc_key.len))
277 {
278 BSL_LOG_ERR("Cannot get registry key");
279 goto error;
280 }
281 ASSERT_PROPERTY(content_enc_key.len > 0);
282 ASSERT_PROPERTY(content_enc_key.ptr == NULL);
283 }
284 else
285 {
286 if (bcb_context->test_content_enc_key.len > 0)
287 {
288 ASSERT_PROPERTY(content_enc_key.len >= bcb_context->test_content_enc_key.len);
289 BSL_LOG_WARNING("Using CEK from test parameter");
290 memcpy(content_enc_key.ptr, bcb_context->test_content_enc_key.ptr, bcb_context->test_content_enc_key.len);
291 content_enc_key.len = bcb_context->test_content_enc_key.len;
292 }
293 else
294 {
295 const size_t keysize = is_aes128 ? 16 : 32;
296 BSL_LOG_DEBUG("Generating %lu bit AES key", keysize * 8);
297 if (BSL_SUCCESS != BSL_Crypto_GenKey(content_enc_key.ptr, keysize))
298 {
299 BSL_LOG_ERR("Failed to generate AES key");
300 goto error;
301 }
302 }
303
304 if (BSL_SUCCESS != BSL_Data_InitBuffer(&bcb_context->wrapped_key, BSLX_MAX_KEYLEN))
305 {
306 BSL_LOG_ERR("Failed to allocate wrapped key");
307 goto error;
308 }
309
310 int wrap_result = BSL_Crypto_WrapKey(&bcb_context->wrapped_key, content_enc_key, bcb_context->key_id, aes_mode);
311 if (BSL_SUCCESS != wrap_result)
312 {
313 BSL_LOG_ERR("Failed to wrap AES key");
314 goto error;
315 }
316 }
317
318 BSL_Cipher_t cipher = { 0 };
319 int cipher_init = BSL_Cipher_Init(&cipher, BSL_CRYPTO_ENCRYPT, aes_mode, bcb_context->iv.ptr, bcb_context->iv.len,
320 content_enc_key);
321 if (BSL_SUCCESS != cipher_init)
322 {
323 BSL_LOG_ERR("Failed to init BCB AES cipher");
324 goto error;
325 }
326
327 if (BSL_SUCCESS != BSL_Cipher_AddAAD(&cipher, bcb_context->aad.ptr, bcb_context->aad.len))
328 {
329 BSL_LOG_ERR("Failed to add AAD");
330 goto error;
331 }
332
333 BSL_Data_t plaintext_data = { 0 };
334 BSL_Data_InitView(&plaintext_data, bcb_context->target_block.btsd_len, bcb_context->target_block.btsd);
335 int nbytes = BSL_Cipher_AddData(&cipher, plaintext_data, bcb_context->btsd_replacement);
336 if (nbytes < 0)
337 {
338 BSL_LOG_ERR("Encrypting plaintext BTSD failed");
339 goto error;
340 }
341 const size_t ciphertext_len = (size_t)nbytes;
342 ASSERT_PROPERTY(ciphertext_len >= plaintext_data.len);
343
344 ASSERT_PROPERTY(ciphertext_len < bcb_context->btsd_replacement.len);
345 uint8_t aes_extra[BSLX_MAX_AES_PAD];
346 memset(aes_extra, 0, sizeof(aes_extra));
347 BSL_Data_t remainder_data = { 0 };
348 BSL_Data_InitView(&remainder_data, sizeof(aes_extra), aes_extra);
349 int extra_bytes = BSL_Cipher_FinalizeData(&cipher, &remainder_data);
350 if (extra_bytes < 0)
351 {
352 BSL_LOG_ERR("Finalizing AES failed");
353 goto error;
354 }
355 const size_t extra_bytelen = (size_t)extra_bytes;
356
357 // "Finalizing" drains any remaining bytes out of the cipher context
358 // and appends them to the ciphertext.
359 const size_t finalized_len = ciphertext_len + extra_bytelen;
360 BSL_Data_Resize(&bcb_context->btsd_replacement, finalized_len);
361
362 BSL_Data_InitBuffer(&bcb_context->authtag, BSL_CRYPTO_AESGCM_AUTH_TAG_LEN);
363 if (BSL_SUCCESS != BSL_Cipher_GetTag(&cipher, (void **)&bcb_context->authtag.ptr))
364 {
365 BSL_LOG_ERR("Failed to get authentication tag");
366 goto error;
367 }
368
369 CHK_POSTCONDITION(bcb_context->btsd_replacement.ptr != NULL);
370 CHK_POSTCONDITION(bcb_context->btsd_replacement.len == ciphertext_len);
371
372 BSL_Data_Deinit(&content_enc_key);
373 BSL_Data_Deinit(&bcb_context->wrapped_key);
374 BSL_Cipher_Deinit(&cipher);
375 return BSL_SUCCESS;
376 // Do any releasing
377error:
378 BSL_Data_Deinit(&content_enc_key);
379 BSL_Data_Deinit(&bcb_context->wrapped_key);
380 BSL_Cipher_Deinit(&cipher);
382}
383
384int BSLX_BCB_GetParams(const BSL_BundleRef_t *bundle, BSLX_BCB_t *bcb_context, const BSL_SecOper_t *sec_oper)
385{
386 CHK_ARG_NONNULL(bundle);
387 CHK_ARG_NONNULL(bcb_context);
388 CHK_ARG_NONNULL(sec_oper);
389
390 CHK_PRECONDITION(bcb_context->target_block.block_num > 0);
391 CHK_PRECONDITION(bcb_context->target_block.btsd != NULL);
392 CHK_PRECONDITION(bcb_context->target_block.btsd_len > 0);
393
394 for (size_t param_index = 0; param_index < BSL_SecOper_CountParams(sec_oper); param_index++)
395 {
396 const BSL_SecParam_t *param = BSL_SecOper_GetParamAt(sec_oper, param_index);
397 bool is_int = BSL_SecParam_IsInt64(param);
398
399 uint64_t param_id = BSL_SecParam_GetId(param);
400 BSL_LOG_DEBUG("BCB parsing param id %lu", param_id);
401 switch (param_id)
402 {
403 case RFC9173_BCB_SECPARAM_IV:
404 {
405 assert(!is_int);
406 BSL_Data_t as_data;
407 if (BSL_SecParam_GetAsBytestr(param, &as_data) < 0)
408 {
409 bcb_context->err_count++;
410 break;
411 }
412 if (BSL_Data_InitView(&bcb_context->iv, as_data.len, as_data.ptr) < 0)
413 {
414 bcb_context->err_count++;
415 break;
416 }
417 break;
418 }
419 case RFC9173_BCB_SECPARAM_AESVARIANT:
420 {
421 BSL_LOG_DEBUG("BCB parsing AES variant (optid=%lu)", param_id);
422 assert(is_int);
423 bcb_context->aes_variant = BSL_SecParam_GetAsUInt64(param);
424 if (bcb_context->aes_variant < RFC9173_BCB_AES_VARIANT_A128GCM
425 || bcb_context->aes_variant > RFC9173_BCB_AES_VARIANT_A256GCM)
426 {
427 BSL_LOG_ERR("Unknown AES variant %lu", bcb_context->aes_variant);
428 bcb_context->err_count++;
429 }
430 break;
431 }
432 case RFC9173_BCB_SECPARAM_WRAPPEDKEY:
433 {
434 BSL_LOG_DEBUG("BCB parsing Wrapped key parameter (optid=%lu)", param_id);
435 assert(!is_int);
436 BSL_Data_t as_data;
437 if (BSL_SecParam_GetAsBytestr(param, &as_data) < 0)
438 {
439 bcb_context->err_count++;
440 break;
441 }
442 if (BSL_Data_InitView(&bcb_context->wrapped_key, as_data.len, as_data.ptr) < 0)
443 {
444 BSL_LOG_ERR("Could not get view of wrapped key");
445 bcb_context->err_count++;
446 break;
447 }
448 break;
449 }
450 case RFC9173_BCB_SECPARAM_AADSCOPE:
451 {
452 assert(is_int);
453 uint64_t aad_scope = BSL_SecParam_GetAsUInt64(param);
454 BSL_LOG_DEBUG("Param[%lu]: AAD_SCOPE value = %lu", param_id, aad_scope);
455 if ((aad_scope & RFC9173_BCB_AADSCOPEFLAGID_INC_PRIM_BLOCK) == 0)
456 {
457 BSL_LOG_DEBUG("BCB AAD does not contain primary block flag");
458 bcb_context->skip_aad_prim_block = true;
459 }
460 if ((aad_scope & RFC9173_BCB_AADSCOPEFLAGID_INC_TARGET_HEADER) == 0)
461 {
462 BSL_LOG_DEBUG("BCB AAD does not contain target block flag");
463 bcb_context->skip_aad_target_block = true;
464 }
465 if ((aad_scope & RFC9173_BCB_AADSCOPEFLAGID_INC_SECURITY_HEADER) == 0)
466 {
467 BSL_LOG_DEBUG("BCB AAD does not contain security header");
468 bcb_context->skip_aad_sec_block = true;
469 }
470 break;
471 }
473 {
474 assert(is_int);
475 bcb_context->key_id = BSL_SecParam_GetAsUInt64(param);
476 BSL_LOG_DEBUG("Param[%lu]: KEY_ID value = %lu", param_id, bcb_context->key_id);
477 BSL_LOG_DEBUG("Key ID = %lu", bcb_context->key_id);
478 break;
479 }
481 {
482 BSL_LOG_DEBUG("BCB using fixed key from test harness");
483 BSL_SecParam_GetAsBytestr(param, &bcb_context->test_content_enc_key);
484 break;
485 }
486 case BSL_SECPARAM_TYPE_AUTH_TAG:
487 {
488 BSL_LOG_DEBUG("Parsing auth tag");
489 BSL_SecParam_GetAsBytestr(param, &bcb_context->authtag);
490 break;
491 }
492 case BSL_SECPARAM_TYPE_IV:
493 {
494 // If we need to pass in an IV for testing purposes.
495 BSL_LOG_DEBUG("Param[%lu]: USE TEST INITIALIZATION VECTOR", param_id);
496 BSL_SecParam_GetAsBytestr(param, &bcb_context->iv);
497 break;
498 }
500 {
501 const uint64_t arg_val = BSL_SecParam_GetAsUInt64(param);
502 BSL_LOG_DEBUG("Param[%lu]: USE_WRAPPED_KEY value = %lu", param_id, arg_val);
503 bcb_context->skip_keywrap = (arg_val == 0);
504 break;
505 }
506 default:
507 {
508 BSL_LOG_ERR("Param[%lu]: INVALID ???", param_id);
509 bcb_context->err_count++;
510 }
511 }
512 }
513
514 if (!bcb_context->skip_aad_sec_block)
515 {
516 // If we are instructed to skip AAD check of the security block
517 // then we don't have to worry about checking it.a
518 const uint64_t sec_blk_num = BSL_SecOper_GetSecurityBlockNum(sec_oper);
519 const int sec_blk_res = BSL_BundleCtx_GetBlockMetadata(bundle, sec_blk_num, &bcb_context->sec_block);
520 if (BSL_SUCCESS != sec_blk_res)
521 {
522 BSL_LOG_ERR("Failed to get security block");
524 }
525 }
526
527 return BSL_SUCCESS;
528}
529
530int BSLX_BCB_Init(BSLX_BCB_t *bcb_context, const BSL_BundleRef_t *bundle, const BSL_SecOper_t *sec_oper)
531{
532 CHK_ARG_NONNULL(bcb_context);
533 CHK_ARG_NONNULL(bundle);
534 CHK_ARG_NONNULL(sec_oper);
535
536 memset(bcb_context, 0, sizeof(*bcb_context));
537
538 // Over-allocate space for any padding gets added in.
539 const size_t new_btsd_len = bcb_context->target_block.btsd_len + 2048;
540 if (BSL_SUCCESS != BSL_Data_InitBuffer(&bcb_context->btsd_replacement, new_btsd_len))
541 {
542 BSL_LOG_ERR("Failed to allocate BTSD double buffer");
544 }
545
546 if (BSL_SUCCESS != BSL_Data_InitBuffer(&bcb_context->debugstr, 512))
547 {
548 BSL_LOG_ERR("Failed to allocated debug str");
550 }
551
552 bcb_context->crypto_mode = BSL_SecOper_IsRoleSource(sec_oper) == true ? BSL_CRYPTO_ENCRYPT : BSL_CRYPTO_DECRYPT;
553
554 if (BSL_SUCCESS != BSL_BundleCtx_GetBundleMetadata(bundle, &bcb_context->primary_block))
555 {
556 BSL_LOG_ERR("Failed to get bundle metatadata");
558 }
559
560 // The bundle must have at least one canonical block...
561 CHK_PROPERTY(bcb_context->primary_block.block_count > 0);
562
563 if (BSL_SUCCESS
564 != BSL_BundleCtx_GetBlockMetadata(bundle, BSL_SecOper_GetTargetBlockNum(sec_oper), &bcb_context->target_block))
565 {
566 BSL_LOG_ERR("Failed to get target block data");
568 }
569
570 CHK_POSTCONDITION(bcb_context->target_block.block_num > 0);
571 CHK_POSTCONDITION(bcb_context->target_block.btsd != NULL);
572 CHK_POSTCONDITION(bcb_context->target_block.btsd_len > 0);
573 CHK_POSTCONDITION(bcb_context->btsd_replacement.ptr != NULL);
574 return BSL_SUCCESS;
575}
576
577static void BSLX_BCB_Deinit(BSLX_BCB_t *bcb_context)
578{
579 ASSERT_ARG_NONNULL(bcb_context);
580
581 BSL_Data_Deinit(&bcb_context->aad);
582 BSL_Data_Deinit(&bcb_context->btsd_replacement);
583 BSL_Data_Deinit(&bcb_context->debugstr);
584 BSL_Data_Deinit(&bcb_context->authtag);
585 BSL_Data_Deinit(&bcb_context->iv);
586 BSL_Data_Deinit(&bcb_context->test_content_enc_key);
587 BSL_Data_Deinit(&bcb_context->test_init_vector);
588 BSL_Data_Deinit(&bcb_context->test_key_enc_key);
589 BSL_Data_Deinit(&bcb_context->wrapped_key);
590 memset(bcb_context, 0, sizeof(*bcb_context));
591}
592
593int BSLX_BCB_Execute(BSL_LibCtx_t *lib, const BSL_BundleRef_t *bundle, const BSL_SecOper_t *sec_oper,
594 BSL_SecOutcome_t *sec_outcome)
595{
596 (void)lib;
597 CHK_ARG_NONNULL(bundle);
598 CHK_ARG_NONNULL(sec_oper);
599 CHK_ARG_NONNULL(sec_outcome);
600
601 CHK_PRECONDITION(BSL_SecOper_GetSecurityBlockNum(sec_oper) > 0);
602
603 BSL_CanonicalBlock_t target_block = { 0 };
604 if (BSL_SUCCESS != BSL_BundleCtx_GetBlockMetadata(bundle, BSL_SecOper_GetTargetBlockNum(sec_oper), &target_block))
605 {
606 BSL_LOG_ERR("Failed to get block data");
608 }
609
610 // Create the BCB context containing all parameters and other metadata.
611 BSLX_BCB_t bcb_context = { 0 };
612
613 // First initialize the BCB context (allocate, etc).
614 if (BSL_SUCCESS != BSLX_BCB_Init(&bcb_context, bundle, sec_oper))
615 {
616 BSL_LOG_ERR("Failed to initialize BCB context");
617 goto error;
618 }
619
620 // Next populate its parameters from the SecParams in the security operations
621 if (BSL_SUCCESS != BSLX_BCB_GetParams(bundle, &bcb_context, sec_oper))
622 {
623 BSL_LOG_ERR("Failed to get BCB parameters");
624 goto error;
625 }
626
627 // Compute the Addition Authenticated Data for authenticated crypto
628 if (BSL_SUCCESS != BSLX_BCB_ComputeAAD(&bcb_context))
629 {
630 BSL_LOG_ERR("Failed to compute AAD");
631 goto error;
632 }
633
634 // Select whether to call the encrypt or decrypt function
635 int (*crypto_fn)(BSLX_BCB_t *) = BSL_SecOper_IsRoleAccepter(sec_oper) ? BSLX_BCB_Decrypt : BSLX_BCB_Encrypt;
636
637 // Perform the encryption/decryption
638 if (BSL_SUCCESS != crypto_fn(&bcb_context))
639 {
640 BSL_LOG_ERR("Failed to perform cryptographic action");
641 goto error;
642 }
643
644 // Re-allocated the target block's BTSD, since enc/dec may slightly change its size.
645 const uint64_t target_blk_id = BSL_SecOper_GetTargetBlockNum(sec_oper);
646 if (BSL_SUCCESS
647 != BSL_BundleCtx_ReallocBTSD((BSL_BundleRef_t *)bundle, target_blk_id, bcb_context.btsd_replacement.len))
648 {
649 BSL_LOG_ERR("Failed to replace target BTSD");
650 goto error;
651 }
652
653 // Refresh the block metadata to account for change in size.
654 if (BSL_SUCCESS != BSL_BundleCtx_GetBlockMetadata(bundle, BSL_SecOper_GetTargetBlockNum(sec_oper), &target_block))
655 {
656 BSL_LOG_ERR("Failed to get block data");
657 goto error;
658 }
659 ASSERT_PROPERTY(target_block.btsd_len == bcb_context.btsd_replacement.len);
660 // Copy the encrypted/decrypted data into the blocks newly reallocated BTSD space.
661 memcpy(target_block.btsd, bcb_context.btsd_replacement.ptr, bcb_context.btsd_replacement.len);
662
663 // Generally we expect an auth tag with the encryption
664 // If present, append it to the result.
665 if (bcb_context.authtag.len > 0)
666 {
667 BSL_SecResult_t *auth_tag = calloc(1, BSL_SecResult_Sizeof());
668 if (BSL_SUCCESS
669 != BSL_SecResult_Init(auth_tag, RFC9173_BCB_RESULTID_AUTHTAG, RFC9173_CONTEXTID_BCB_AES_GCM,
670 BSL_SecOper_GetTargetBlockNum(sec_oper), bcb_context.authtag))
671 {
672 BSL_LOG_ERR("Failed to append BCB auth tag");
673 goto error;
674 }
675 else
676 {
677 BSL_LOG_INFO("Appending BCB Auth Tag");
678 BSL_SecOutcome_AppendResult(sec_outcome, auth_tag);
679 }
680 free(auth_tag);
681 }
682
683 BSLX_BCB_Deinit(&bcb_context);
684 return BSL_SUCCESS;
685
686error:
687
688 BSLX_BCB_Deinit(&bcb_context);
690}
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_USE_WRAPPED_KEY
This must be explicitly set, and set to 0, to avoid generating a wrapped key.
@ 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_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...
#define BSL_LOG_ERR(...)
This is an overloaded member function, provided for convenience. It differs from the above function o...
@ BSL_ERR_NOT_IMPLEMENTED
Requested functionality not yet implemented.
@ 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_SUCCESS
Placeholder for non-error code.
@ BSL_ERR_HOST_CALLBACK_FAILED
Callback to the host BPA returned a non-zero code.
int BSL_Crypto_GenIV(void *buf, int size)
Generate initialization vector (IV) for AES-GCM for BCBs.
int BSL_Cipher_AddData(BSL_Cipher_t *cipher_ctx, BSL_Data_t plaintext, BSL_Data_t ciphertext)
int BSLB_Crypto_GetRegistryKey(uint64_t keyid, const uint8_t **secret, size_t *secret_len)
Get pointers to an existing key, if present.
int BSL_Cipher_Init(BSL_Cipher_t *cipher_ctx, BSL_CipherMode_e enc, BSL_CryptoCipherAESVariant_e aes_var, const void *init_vec, int iv_len, BSL_Data_t content_enc_key)
Initialize crypto context resources and set as encoding or decoding.
int BSL_Crypto_WrapKey(BSL_Data_t *wrapped_key, BSL_Data_t cek, size_t content_key_id, size_t aes_variant)
int BSL_Cipher_Deinit(BSL_Cipher_t *cipher_ctx)
De-initialize crypto context resources.
int BSL_Cipher_AddAAD(BSL_Cipher_t *cipher_ctx, const void *aad, int aad_len)
Add additional authenticated data (AAD) to cipher context.
int BSL_Crypto_UnwrapKey(BSL_Data_t *unwrapped_key_output, BSL_Data_t wrapped_key_plaintext, size_t key_id, size_t aes_variant)
int BSL_Cipher_SetTag(BSL_Cipher_t *cipher_ctx, const void *tag)
Set the tag of the crypto operation.
int BSL_Cipher_GetTag(BSL_Cipher_t *cipher_ctx, void **tag)
Get the tag of the crypto operation.
Abstract interface for crypto processing.
@ BSL_CRYPTO_ENCRYPT
We use undefined for zero, in case this value is never explicitly set and is just zero by default.
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_ReallocBTSD(BSL_BundleRef_t *bundle, uint64_t block_num, size_t bytesize)
Requests the re-allocation of a block's BTSD, useful for BCB.
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_IsRoleSource(const BSL_SecOper_t *self)
Return true if this security operation's role is SOURCE.
bool BSL_SecOper_IsRoleAccepter(const BSL_SecOper_t *self)
Return true if this security operation's role is Acceptor.
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
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_Resize(BSL_Data_t *data, size_t len)
Resize the data, copying if necessary.
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.
int BSL_Data_InitView(BSL_Data_t *data, size_t len, const BSL_DataPtr_t src)
Initialize a data struct as an overlay on optional external data.
Contains constants as defined in IETF RFC 9173 (Default Security Context for BPSec)
@ RFC9173_BCB_RESULTID_AUTHTAG
https://www.rfc-editor.org/rfc/rfc9173.html#name-bcb-aes-gcm-security-result
Definition rfc9173.h:95
BCB encryption context with crypto primitives.
Reference to a Bundle owned and stored in the host BPA.
Structure containing parsed Canonical Block fields.
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.
Struct def for cipher operation context.
Heap data storage and views.
size_t len
Size of the data buffer.
BSL_DataPtr_t ptr
Pointer to the front of the buffer.
Concrete definition of library context.
size_t block_count
Helpful count of total canonical blocks in bundle, not a field of the header.