Commit graph

9612 commits

Author SHA1 Message Date
bunnie
c4ef7baabb add image size checking in image generator
flags when the kernel is too big now
2025-12-06 18:21:57 +08:00
bunnie
6080667deb
move console into swap
we've run out of space in the main image, so this gives us
some breathing room.
2025-12-06 18:21:14 +08:00
bunnie
7964eb8aef
Merge pull request #750 from betrusted-io/fix-hazardous-debug
fix argument to hazardous-debug print
2025-12-05 19:23:15 +03:00
bunnie
b012038c1d
fix argument to hazardous-debug print
this allows us to check that things are being done correctly
in CI.
2025-12-06 00:16:36 +08:00
bunnie
e3377f8846
Merge pull request #749 from betrusted-io/boot-hardening
Boot Glitch Hardening
2025-12-05 19:03:01 +03:00
bunnie
6c6bfce02b
update dependencies for KAT test in boot0 2025-12-05 23:27:24 +08:00
bunnie
3466115cce
harden loader/kernel/app/swap checks
At this point, some of the keys are partially locked out
which makes reacting to an attack slightly less effective
(keys are now locked into a particular process space configuration
which is not available in the loader's default config).

The reaction at this point sums up to seeing if the image is
a developer image, and if so, ensuring that the developer mode
bit is set (which would indicate that the keys have been
erased). I suppose an attacker could get around this by glitching
to some code that sets developer mode without also erasing
the keys. This weakness needs to be explored and hardened against.
2025-12-05 23:17:11 +08:00
bunnie
50d32ecb42
upgrade audit routines to use the new signature checking API 2025-12-05 23:16:04 +08:00
bunnie
8be0f1004b
upgrade boot1 path to implement signature hardening
multi-pass signature checking and jump target hardening
per boot0 standards implemented here
2025-12-05 23:15:15 +08:00
bunnie
006eab2084
add multi-pass validation in paranoid mode to boot0
this patch uses the previously modified APIs and implements
a multi-pass check on signatures in the case that paranoid
mode is turned on. This may effectively double the boot time but
it also reduces the chance of a successful glitch attack
on signature validation by a multiple of the glitch
success probability.

this also updates other API calls and implements the
XOR-on-target-address code.
2025-12-05 23:12:15 +08:00
bunnie
ae120c7632
add a known answer test after loading hash constants
This test helps ensure that attempts to tamper with the
hasher constant loading don't propagate through to actual
usages of the hasher.
2025-12-05 23:10:22 +08:00
bunnie
b99b4cb665
cleanup signature checking API
Signature checking parameters are now consolidated into
a single "SecurityConfiguration" record. This allows the
sum total of security state transitions to be summarized in
the bao1x-api/src/pubkeys/mod.rs file, easing maintenance
and audit.

Reaction to the signature check is split into a `hardened_erase_policy`
API call which can take the results of the signature check and
react to it if necessary.

This allows the signature check routine to be used for both
audit (where reaction is not necessary) and for live testing
of the code (where reaction is required). It also simplifies
the implementation of double-checking signatures in the case
of paranoid mode.

Another important improvement is that the signature checking
API outputs the target address for the jump, but masked with
an XOR of the function code of the signed block. The purpose
of the XOR mask isn't to obfuscate the value; rather, it's
to prevent there being a single, simple, fixed-constant
jump instruction laying around that a glitcher can use as
a target: instead, a pair of registers must be loaded
with the target and its mask. This is an example of what
the final jump looks like:

```
60003a8e:	ffffffff          	.word	0xffffffff
60003a92:	0440006f          	j	60003ad6 <bao1x_hal::hardening::die>
60003a96:	ffffffff          	.word	0xffffffff
60003a9a:	167d                	addi	a2,a2,-1
60003a9c:	fe71                	bnez	a2,60003a78 <rust_entry+0x2f74>
60003a9e:	a00d                	j	60003ac0 <rust_entry+0x2fbc>
60003aa0:	0360006f          	j	60003ad6 <bao1x_hal::hardening::die>
60003aa4:	ffffffff          	.word	0xffffffff
60003aa8:	02e0006f          	j	60003ad6 <bao1x_hal::hardening::die>
60003aac:	ffffffff          	.word	0xffffffff
60003ab0:	0260006f          	j	60003ad6 <bao1x_hal::hardening::die>
60003ab4:	ffffffff          	.word	0xffffffff
60003ab8:	01e0006f          	j	60003ad6 <bao1x_hal::hardening::die>
60003abc:	ffffffff          	.word	0xffffffff
60003ac0:	0149c533          	xor	a0,s3,s4
60003ac4:	600805b7          	lui	a1,0x60080
60003ac8:	d0058593          	addi	a1,a1,-768 # 6007fd00 <_etext+0x6e9dc>
60003acc:	82aa                	mv	t0,a0
60003ace:	852e                	mv	a0,a1
60003ad0:	4581                	li	a1,0
60003ad2:	8282                	jr	t0
```

So here you can see the alternating bollards in the region that
will cause any glitches that don't land exactly right to
either halt the machine or cause a reaction.

Line 0x6003ac0 is where the xor happens to compute the target
address. Should a glitcher land on that address, `s3` and `s4`
will need to be loaded with the target address and a value when
XOR'd with it that yields a meaningful result. While there is
a non-zero chance that this can be arranged, it's definitely
not as easy as targeting a jump-to-fixed address exit sequence.
2025-12-05 22:57:34 +08:00
bunnie
d9d146352f
ensure that hardened_get2 is used correctly with an assert 2025-12-05 22:43:49 +08:00
bunnie
32ffba0931
introduce security configurations
The management of different security configurations was getting
a bit out of hand, so all the security configurations used by
the system and their transitions are now consolidated into a single
file, This will make auditing and checking the transitions a lot
easier.
2025-12-05 21:37:21 +08:00
bunnie
940f3c057c cleanup warning 2025-12-05 21:36:50 +08:00
bunnie
1dbb65cc97
zerorize backup registers & fix aoram range in zeroize
backup registers are a high priority target on zeroizing
because it would contain the ephemeral unlock secret, e.g.
PIN code.
2025-12-05 00:59:59 +08:00
bunnie
3293578d3e add second pll check in loader 2025-12-04 16:14:59 +08:00
bunnie
9566c1615a
add rand_chacha dependency 2025-12-04 15:41:56 +08:00
bunnie
3f7dce3052
loader hardening
The loader is only lightly hardened at this point. Some minmal
random delay + bollards inserted. The signature check routine
inherits all the hardening of boot0 because it uses the same
code. PLL mode is checked at least once.

more loader hardening will happen in a future PR - at the
moment, we're focused on boot0/boot1 hardening.
2025-12-04 15:38:57 +08:00
bunnie
4b25e24d7e
harden boot1
boot1 hardening is similar to boot0 hardening - bollard & delay
insertion, checking that we're in PLL mode. Also the first phase
mesh results are checked and second phase is setup for the loader
to finally check.

clocks are still local to the routine - there's a to-do to consolidate
that routine into the API layer later on.
2025-12-04 15:36:55 +08:00
bunnie
9217b9aff5
add a quick health check to the RO trng
takes 8 samples and makes sure those values aren't repeated in the
next 8 samples.

has a ~1 in 500 million chance of giving a false positive. But
generally should catch: stuck-at fault, and also, a highly trained
oscillator fault.
2025-12-04 15:34:39 +08:00
bunnie
c126f7b4f1
add repl commands to boot1 for security
- add `paranoid` command - when set, puts the chip into
paranoid mode. Not set by default because we need to check that
the security countermeasures are not too aggressive
- `lockdown` now revokes all developer keys in both main and
redundant array, and sets paranoid mode
- api fixes for sig validate
- audit now prints results of paranoid mode and attack count
2025-12-04 15:32:10 +08:00
bunnie
9e5c57b7de
inline the pll check
this prevents it from being a single area that has to be patched
to bypass the pll check
2025-12-04 15:30:43 +08:00
bunnie
1c210b3541
other boot0 hardening
- harden the check that the boot0 public keys match those in the
data array
- security mesh setup
- insertion of random delays & bollards
- upgrade API on signature verification to allow for random delays
during the signature check
2025-12-04 15:28:52 +08:00
bunnie
b00acba907
boot0 platform hardening
- paranoid mode entry is implemented here. The main outcome of
paranoid mode is that when activated, the system will automatically
reset anytime a voltage glitch is detected.

- clean up PLL mode setting. For boot0, the mode is fixed & hardened
to 175MHz CPU operation, running off the PLL, under the theory that
running at this speed makes glitch attacks harder as the cycle time
is now 5.71ns, and simply disturbing the XTAL clock doesn't cause
the PLL to straight-up stop.

- some hardening to ensure that we are actually in PLL mode, and
that the switch to PLL mode wasn't glitched over
2025-12-04 15:15:16 +08:00
bunnie
78036d71dc
add code to check the flag
there's a dummy flag checked in, and this code helps check that
the flag is treated correctly during CI testing
2025-12-04 15:10:51 +08:00
bunnie
d8f4ef9fe0
baremetal changes
- update to use new clock API
- add test routines for security sensors
2025-12-04 15:07:51 +08:00
bunnie
362124127e
add redundant counters, paranoid mode, attack counters
This allocates some additional one way counters dedicated
to hardening:

- Paranoid mode is duplicated in slots 65 & 67
- An attack counter is in slot 66
- Redundant revocation counters are seated in slot 68

The primary revocation counters are in slot 116. This means
that cutting out the revocation counters would probably require
at least two edits to the memory array - simply cutting the
word addressing line for those columns might be enough to
defeat a counter.

Paranoid mode duplicate is stored somewhat close to the
primary counter, which means it could be subject to a single
line cut to fully defeat the counter, but the space is getting
pretty crowded so I'll leave it like that; I really want to
leave the bottom 64 slots available for application use.

A "flag" key is allocated, plus a dummy flag is committed
to the repo. This is a value that, if retrieved, would
ostensibly bring the retriever glory and bounty, to the
extent that any glory or bounty is to be had (ps: I'm poor
and this project is obscure). The actual flag, of course,
is not in the repo...I hope!

The flag value is different from all other values in that
this is the only shared, common secret across all devices.

All other device secrets are generated on a per-device
basis from the TRNGs. So the flag needs some special treatment
such that it's not overwritten during device keying.

The flag exists because I'm hoping that anyone who manages
to extract it will also provide a helpful explanation of
the procedure to get it out, so that the system could be
patched (if the error is patchable) or rev'd in future
silicon. That being said, a flag retrieval is not necessarily
equal to a full break of security across all devices because
as mentioned above, most device secrets are on a per-device
basis. The flag represents then, the amount of effort necessary
to apply to every device to retrieve the secrets within.
2025-12-04 14:56:07 +08:00
bunnie
31385a5599
start moving clock routines into an API library
clock setting calls, for legacy reasons, are duplicated in all the
stages of the bootloaders. This is a start toward moving these routines
into a common set of calls that improves maintainability.
2025-12-04 14:54:26 +08:00
bunnie
bd08328530
add bollard macro and HardenedBool
These macros are added to the platform-agnostic API crate.

bollard is a macro that can respond to the following argument
formats:

bollard!(): inserts 4 illegal instructions and a jump over them
bollard!(#): inserts # of illegal instructions and a jump over them
bollard!(f, #): inserts # of an interleave of illegal instructions
and a jump to f

the last form is intended to "up the ante" by including a call
to a routine that can shut down the chip and/or wipe secrets
should the defender choose to do that. The other ones just
trampoline into an illegal instruction vector which is a fairly
weak defense because the CPU could once again get glitched out
of that.

HardenedBool is a boolean represented by a high-hamming distance
numeric value so that single-bit flips just lead to an invalid
bool, instead of a change in the meaning of the bool.
2025-12-04 14:50:33 +08:00
bunnie
75fb1a1889
Harden the signature check routine
- key revocation check is fully duplicated and tested twice
- bollards & random delays added throughout the code. Random
delays require passing in a csprng object from the calling
environment.
- the primary go/no-go decision on whether a signature passes
or not is unfortunately not hardenable because the API is in
a third party crate. However, the regions around that call are
random-delayed and surrounded with bollards
- the state bits that determine whether the system is secure
and/or in developer mode are implemented using HardenedBool
- erase_secrets has some delays added to it as well as bollards.
However, it does remain a weakness that an attacker
could pull RRAM power during the erase cycle by just isolating
the RRAM power supply and putting a fast current limit on it,
thus preventing effective erasure by starving the circuit
of power.

Nothing we can really do about an active attack on the power
supply to prevent erasure, I think. It is unfortunately required
by design to have an isolated power supply for the RRAM to perform
elevated-voltage forming at CP time, and so, it should always
be possible to limit the current going into it thus preventing,
at least somewhat, any programming operations on the array.
2025-12-04 14:36:28 +08:00
bunnie
05af4f3f62
add hardened_get() and hardened_get2() to one way counters
One way counters are used ot record some security-critical properties,
such as key revocations and paranoid mode.

Two methods of retrieving the counters so that they are hardened
are provide here. Both of them rely on the fact that any value
other than 0 for the counter means it is set.

`hardened_get()` retrieves the counter value and sums it several
times. It does this *twice*, and returns *both* values as a tuple.
By returning both values as a tuple, it reduces the likelihood
that the compiler optimizes out the redundant read. The receiver
should implement serial checks that operate on the hardened_get()
result (i.e., test one value of the tuple, then test the other
value of the tuple redundantly, instead of OR'ing them together
into a single test)

`hardened_get2()` is for counters that are fully duplicated in
the array. For extremely critical counters, they are stored in
two physically separate elements. This is done to make bypass
of the counter harder than just FIB'ing out a single bit in
the memory array. In the case of `hardened_get2()`, a tuple
is returned, but instead of reading the same value twice, the
tuple corresponds to the summed value over each of the redundant
counters.
2025-12-04 14:29:30 +08:00
bunnie
9294c06d45
Add glitch hardening library
This library contains the following primitives:

check_pll() - checks that the PLL is the primary clock source.
This is important because allowing direct clocking of the system
from the external clock pin makes glitching much, much easier.

die() - a routine that implements a reaction to attacks. At the
moment, we just note attacks and then halt the machine. Eventually,
this could be upgraded to be more reactive, e.g. erasing secrets
or bricking the chip.

Csprng - this is a chacha8 cipher seeded with ring oscillator
TRNG data, plus whatever tiny bit of entropy we can scavenge
from uninitialized RAM (to make it so that it's not as trivial
as cutting the RO wire and tying it to 0 to bypass the library).
There's also a tiny health check on the RO before using it, again,
to make it harder than just cutting the RO wire. The sole purpose
of the Csprng is to generate random delays that frustrate glitching
attacks. The delay is currently tuned to a range of 0-255 iterations
of a loop.

paranoid_mode() - turns on fully automatic reactive sensor
countermeasures. Whenever a voltage glitch is detected, the system
will just reboot.

mesh countermeasures - these set up the secure mesh and the
reaction policy to tamper detection on the secure meshes

apply_attack_policy() - an API call that applies the currently
determined countermeasure in case that the detected attacks
counter has gone above a threshold. The reason we don't simply
react right away is that some countermeasures are fairly
sensitive, and *also*, very importantly, the chip *is* packaged
in a CSP and thus especially for dabao users you will expect
to see random trips of the attack sensors due to environmental
noise (photoflashes, nearby lightning strikes, etc.).
2025-12-04 13:34:01 +08:00
bunnie
4cd712b2b0
Merge pull request #747 from betrusted-io/chaffing
AES Chaffing
2025-12-01 21:45:36 +03:00
bunnie
3663ea1276 revert inadvertent testing flag that was checked in
this only makes sense for testing on specific builds.
2025-12-02 02:39:28 +08:00
bunnie
9b54fdb64f fix dabao target dependencies 2025-12-02 02:27:01 +08:00
bunnie
988570d6a6 update lockfile dependencies 2025-12-02 01:43:32 +08:00
bunnie
46fb57628e remove aes dependency from kernel
this is a false dependency, there is no AES in the kernel
2025-12-02 01:42:59 +08:00
bunnie
52215251a4 add a random seed to the environment
this is randomly genverated on boot and inserted into the
environment. it is unique per-PID.

This is useful for seeding psuedorandom number generators,
especially in environments where syscalls are not possible.
2025-12-02 01:40:49 +08:00
bunnie
01475137bb add code to test the random seed 2025-12-02 01:40:39 +08:00
bunnie
fcc6fc5538 add chaffing feature to the swapper
the main imagined attack vector on the swapper is recovery
of the AES key through side channel analysis.
2025-12-02 01:06:36 +08:00
bunnie
5b4d6c1932 add benchmark data on chaffing
unchaffed AES is 5.36us/block
chaffed AES is 10.27us/block

so ~2x overhead for chaffing - about what we expect for the
implementation.
2025-12-02 01:05:26 +08:00
bunnie
da44e98257 add chaffing implementation to AES 2025-12-02 01:04:17 +08:00
bunnie
712ee68df5
Merge pull request #746 from betrusted-io/build-fixes
fix TTS target API change
2025-11-30 17:27:53 +03:00
bunnie
9034a08b5e fix TTS target API change 2025-11-30 22:21:31 +08:00
bunnie
cbe5c4ae4e
Merge pull request #745 from betrusted-io/towards-time-setting
Vault2: Set time & other UI improvements
2025-11-30 17:12:51 +03:00
bunnie
d9a65a51d9 fix hosted mode 2025-11-30 21:56:32 +08:00
bunnie
7ec01905aa add password creation, and password generator configuration
also vendors in the password generator so that we can customize
special characters
2025-11-30 21:34:05 +08:00
bunnie
852a12645b round out stateful list creation in the ux-api libraries 2025-11-30 21:33:04 +08:00
bunnie
381dee01eb fix interfaces in GAM for stateful lists 2025-11-30 21:32:26 +08:00