pkcs11 store: tighten power-fail assert, rebase F4 footprint limits

vault_obj_read() now separates "object absent" from a failed read, so the
power-fail test rejects a corrupted vault instead of accepting any negative.
hal_cache_invalidate() shrank 120 -> 44 bytes; the 48 it still costs every
STM32F407 build is folded into the test-size-all limits.
pull/873/head
Daniele Lacamera 2026-09-10 19:23:57 +02:00
parent 9b06b907f8
commit 3d5bebeefe
4 changed files with 74 additions and 56 deletions

View File

@ -196,26 +196,28 @@ void RAMFUNCTION hal_flash_unlock(void)
FLASH_KEYR = FLASH_KEY2;
}
#if ((FLASH_ACR_ENABLE_INST_CACHE << 2) != FLASH_ACR_RESET_INST_CACHE) || \
((FLASH_ACR_ENABLE_DATA_CACHE << 2) != FLASH_ACR_RESET_DATA_CACHE)
#error "STM32F4: flash cache reset bits are not two positions above the enables"
#endif
/* RM0090 3.5.1: the instruction and data caches keep lines fetched before an
* erase/program, so a read-back through the flash memory map can return
* pre-erase bytes. The reset bits are only writable while the corresponding
* cache is disabled, hence the disable/reset/re-enable dance. */
* pre-erase bytes. A cache reset bit is only writable while its cache is
* disabled, and the reset bits sit two positions above the enable bits
* (ICEN 9 -> ICRST 11, DCEN 10 -> DCRST 12), so one shift covers both. */
void RAMFUNCTION hal_cache_invalidate(void)
{
uint32_t acr = FLASH_ACR;
uint32_t en = acr & (FLASH_ACR_ENABLE_INST_CACHE |
FLASH_ACR_ENABLE_DATA_CACHE);
uint32_t off = acr & ~en;
if (acr & FLASH_ACR_ENABLE_INST_CACHE) {
FLASH_ACR &= ~FLASH_ACR_ENABLE_INST_CACHE;
FLASH_ACR |= FLASH_ACR_RESET_INST_CACHE;
FLASH_ACR &= ~FLASH_ACR_RESET_INST_CACHE;
FLASH_ACR |= FLASH_ACR_ENABLE_INST_CACHE;
}
if (acr & FLASH_ACR_ENABLE_DATA_CACHE) {
FLASH_ACR &= ~FLASH_ACR_ENABLE_DATA_CACHE;
FLASH_ACR |= FLASH_ACR_RESET_DATA_CACHE;
FLASH_ACR &= ~FLASH_ACR_RESET_DATA_CACHE;
FLASH_ACR |= FLASH_ACR_ENABLE_DATA_CACHE;
}
if (en == 0)
return;
FLASH_ACR = off; /* disable the caches that were on */
FLASH_ACR = off | (en << 2); /* set their reset bits */
FLASH_ACR = off; /* release reset */
FLASH_ACR = acr; /* restore the original enables */
}
void RAMFUNCTION hal_flash_lock(void)

View File

@ -98,26 +98,27 @@ void RAMFUNCTION hal_flash_unlock(void)
}
}
#if ((FLASH_ACR_ICEN << 2) != FLASH_ACR_ICRST) || \
((FLASH_ACR_DCEN << 2) != FLASH_ACR_DCRST)
#error "STM32G4: flash cache reset bits are not two positions above the enables"
#endif
/* RM0440 3.3.3: the instruction and data caches keep lines fetched before an
* erase/program, so a read-back through the flash memory map can return
* pre-erase bytes. The reset bits are only writable while the corresponding
* cache is disabled, hence the disable/reset/re-enable dance. */
* pre-erase bytes. A cache reset bit is only writable while its cache is
* disabled, and the reset bits sit two positions above the enable bits
* (ICEN 9 -> ICRST 11, DCEN 10 -> DCRST 12), so one shift covers both. */
void RAMFUNCTION hal_cache_invalidate(void)
{
uint32_t acr = FLASH_ACR;
uint32_t en = acr & (FLASH_ACR_ICEN | FLASH_ACR_DCEN);
uint32_t off = acr & ~en;
if (acr & FLASH_ACR_ICEN) {
FLASH_ACR &= ~FLASH_ACR_ICEN;
FLASH_ACR |= FLASH_ACR_ICRST;
FLASH_ACR &= ~FLASH_ACR_ICRST;
FLASH_ACR |= FLASH_ACR_ICEN;
}
if (acr & FLASH_ACR_DCEN) {
FLASH_ACR &= ~FLASH_ACR_DCEN;
FLASH_ACR |= FLASH_ACR_DCRST;
FLASH_ACR &= ~FLASH_ACR_DCRST;
FLASH_ACR |= FLASH_ACR_DCEN;
}
if (en == 0)
return;
FLASH_ACR = off; /* disable the caches that were on */
FLASH_ACR = off | (en << 2); /* set their reset bits */
FLASH_ACR = off; /* release reset */
FLASH_ACR = acr; /* restore the original enables */
}
void RAMFUNCTION hal_flash_lock(void)

View File

@ -1231,55 +1231,57 @@ test-size-all:
# Several limits below are raised relative to upstream. This branch bumps
# lib/wolfssl to the ti_c25 merge for CHAR_BIT!=8 wide-byte support, which
# costs 4-48 bytes depending on configuration (most of it in the no-ASM
# SP-math and ML-DSA paths). No wolfBoot code changed in these builds, and
# each new value is the measured size, matching upstream's convention.
# SP-math and ML-DSA paths). On top of that, every entry here is an
# STM32F407 build, so each one also carries the flat 48 bytes of
# hal_cache_invalidate() and its call from hal_flash_lock(). Each value
# is the measured size, matching upstream's convention.
# Measured with the CI container (ghcr.io/wolfssl/wolfboot-ci-arm).
make test-size SIGN=NONE LIMIT=5116 NO_ARM_ASM=1
make test-size SIGN=NONE LIMIT=5164 NO_ARM_ASM=1
make keysclean
make test-size SIGN=ED25519 LIMIT=12228 NO_ARM_ASM=1
make test-size SIGN=ED25519 LIMIT=12276 NO_ARM_ASM=1
make keysclean
make test-size SIGN=ECC256 LIMIT=18924 NO_ARM_ASM=1
make test-size SIGN=ECC256 LIMIT=18972 NO_ARM_ASM=1
make clean
make test-size SIGN=ECC256 NO_ASM=1 LIMIT=13968 NO_ARM_ASM=1
make test-size SIGN=ECC256 NO_ASM=1 LIMIT=14016 NO_ARM_ASM=1
make keysclean
make test-size SIGN=RSA2048 LIMIT=11816 NO_ARM_ASM=1
make test-size SIGN=RSA2048 LIMIT=11864 NO_ARM_ASM=1
make clean
make test-size SIGN=RSA2048 NO_ASM=1 LIMIT=12372 NO_ARM_ASM=1
make test-size SIGN=RSA2048 NO_ASM=1 LIMIT=12412 NO_ARM_ASM=1
make keysclean
make test-size SIGN=RSA4096 LIMIT=12116 NO_ARM_ASM=1
make test-size SIGN=RSA4096 LIMIT=12164 NO_ARM_ASM=1
make clean
make test-size SIGN=RSA4096 NO_ASM=1 LIMIT=12660 NO_ARM_ASM=1
make test-size SIGN=RSA4096 NO_ASM=1 LIMIT=12708 NO_ARM_ASM=1
make keysclean
make test-size SIGN=ECC384 LIMIT=19608 NO_ARM_ASM=1
make test-size SIGN=ECC384 LIMIT=19656 NO_ARM_ASM=1
make clean
make test-size SIGN=ECC384 NO_ASM=1 LIMIT=15328 NO_ARM_ASM=1
make test-size SIGN=ECC384 NO_ASM=1 LIMIT=15376 NO_ARM_ASM=1
make keysclean
make test-size SIGN=ED448 LIMIT=14256 NO_ARM_ASM=1
make test-size SIGN=ED448 LIMIT=14288 NO_ARM_ASM=1
make keysclean
make test-size SIGN=RSA3072 LIMIT=11956 NO_ARM_ASM=1
make test-size SIGN=RSA3072 LIMIT=12004 NO_ARM_ASM=1
make clean
make test-size SIGN=RSA3072 NO_ASM=1 LIMIT=12480 NO_ARM_ASM=1
make test-size SIGN=RSA3072 NO_ASM=1 LIMIT=12528 NO_ARM_ASM=1
make keysclean
make test-size SIGN=RSAPSS2048 LIMIT=13748 NO_ARM_ASM=1
make test-size SIGN=RSAPSS2048 LIMIT=13796 NO_ARM_ASM=1
make clean
make test-size SIGN=RSAPSS2048 NO_ASM=1 LIMIT=14304 NO_ARM_ASM=1
make test-size SIGN=RSAPSS2048 NO_ASM=1 LIMIT=14344 NO_ARM_ASM=1
make keysclean
make test-size SIGN=RSAPSS3072 LIMIT=13916 NO_ARM_ASM=1
make test-size SIGN=RSAPSS3072 LIMIT=13964 NO_ARM_ASM=1
make clean
make test-size SIGN=RSAPSS3072 NO_ASM=1 LIMIT=14436 NO_ARM_ASM=1
make test-size SIGN=RSAPSS3072 NO_ASM=1 LIMIT=14484 NO_ARM_ASM=1
make keysclean
make test-size SIGN=RSAPSS4096 LIMIT=14088 NO_ARM_ASM=1
make test-size SIGN=RSAPSS4096 LIMIT=14136 NO_ARM_ASM=1
make clean
make test-size SIGN=RSAPSS4096 NO_ASM=1 LIMIT=14628 NO_ARM_ASM=1
make test-size SIGN=RSAPSS4096 NO_ASM=1 LIMIT=14676 NO_ARM_ASM=1
make keysclean
make test-size SIGN=LMS LMS_LEVELS=2 LMS_HEIGHT=5 LMS_WINTERNITZ=8 \
WOLFBOOT_SMALL_STACK=0 IMAGE_SIGNATURE_SIZE=2644 \
IMAGE_HEADER_SIZE?=5288 LIMIT=8120 NO_ARM_ASM=1
IMAGE_HEADER_SIZE?=5288 LIMIT=8168 NO_ARM_ASM=1
make keysclean
make test-size SIGN=XMSS XMSS_PARAMS='XMSS-SHA2_10_256' \
IMAGE_SIGNATURE_SIZE=2500 IMAGE_HEADER_SIZE?=4096 \
LIMIT=8772 NO_ARM_ASM=1
LIMIT=8820 NO_ARM_ASM=1
make keysclean
make clean
make test-size SIGN=ML_DSA ML_DSA_LEVEL=2 LIMIT=19630 \
make test-size SIGN=ML_DSA ML_DSA_LEVEL=2 LIMIT=19678 \
IMAGE_SIGNATURE_SIZE=2420 IMAGE_HEADER_SIZE?=8192

View File

@ -766,14 +766,22 @@ static int vault_obj_write(int type, CK_ULONG tok, CK_ULONG obj,
return ret;
}
/* "The object is not in the vault" is a legitimate state after a power cut,
* but any other open/read failure means the vault or its metadata is
* damaged. Report the two distinctly so the power-fail test can insist on
* the former and fail on the latter. */
#define VAULT_OBJ_ABSENT (-1000)
static int vault_obj_read(int type, CK_ULONG tok, CK_ULONG obj,
uint8_t *out, int max)
{
void *store = NULL;
int ret = wolfPKCS11_Store_Open(type, tok, obj, 1, &store);
if (ret == NOT_AVAILABLE_E)
return VAULT_OBJ_ABSENT;
if (ret != 0)
return -1;
return ret;
ret = wolfPKCS11_Store_Read(store, out, max);
wolfPKCS11_Store_Close(store);
return ret;
@ -846,9 +854,14 @@ START_TEST (test_power_fail_during_rewrite_never_mixes_generations) {
"payload", crash);
}
else {
ck_assert_msg(ret <= 0,
"power fail at op %d: object read back %d bytes, neither "
"generation nor empty", crash, ret);
/* Only two other outcomes are crash-safe: the object was never
* published, or it is present but truncated to empty by the
* Open-time durability commit. Every other return (a negative
* read error, or a partial payload length) means the vault came
* back damaged. */
ck_assert_msg(ret == VAULT_OBJ_ABSENT || ret == 0,
"power fail at op %d: object read back %d, neither old "
"payload, new payload, empty, nor absent", crash, ret);
}
}
}