this tries to catch the cases that:
- user tried to run the backup without first running "prepare backup..."
- the USB connection is a little flakey and returning bum data
We can only inspect the plaintext portions of the header, which contains
things like protocol version numbers, time stamps, and language codes.
We use the timestamp validation heavily because it's the only field that
isn't almost always going to be a 0 or 1 when correct, which are highly
likely to be reported anyways if there's a problem with the USB link.
This does assume the user sets the time correctly on the device
doing the backup, and on the Precursor itself.
This adds the `--dump` command, which requires a file that is
a copy/paste of a generated virtual to physical table. An example
of this log would look like this:
```
INFO:shellchat::cmds::net_cmd: V|P 6000d000 40799000 (services\shellchat\src\cmds\net_cmd.rs:770)
INFO:shellchat::cmds::net_cmd: V|P 6000e000 4079a000 (services\shellchat\src\cmds\net_cmd.rs:770)
INFO:shellchat::cmds::net_cmd: V|P 6000f000 4079b000 (services\shellchat\src\cmds\net_cmd.rs:770)
INFO:shellchat::cmds::net_cmd: V|P 60010000 4079c000 (services\shellchat\src\cmds\net_cmd.rs:770)
INFO:shellchat::cmds::net_cmd: V|P 60011000 4079d000 (services\shellchat\src\cmds\net_cmd.rs:770)
INFO:shellchat::cmds::net_cmd: V|P 60012000 4079e000 (services\shellchat\src\cmds\net_cmd.rs:770)
INFO:shellchat::cmds::net_cmd: V|P 60013000 4079f000 (services\shellchat\src\cmds\net_cmd.rs:770)
INFO:shellchat::cmds::net_cmd: V|P 60014000 407a0000 (services\shellchat\src\cmds\net_cmd.rs:770)
INFO:shellchat::cmds::net_cmd: V|P 60015000 407a1000 (services\shellchat\src\cmds\net_cmd.rs:770)
```
and so forth. The script can parse this raw log to create the necessary
page table mappings to read a large region of virtual memory and save
it as a contiguous chunk in a file.
It's a bit confusing to run the wrong tool but hopefully there
are ample help messages sprinkled in this to guide the average
user to the right location.
also print the sector data that errors out -- might be a bit
much at the moment but it's very helpful for immmediately
visualizing a loss-of-power event related write corruption
the loader is a little funky, and requires some maintainer hand-holding
due to the split of the page ownership between the root-keys
crate and the graphics-server crate.
Improved docs so I don't forget this detail in the future.
this allows for a quick readout of the version of each of these
artifacts, inside a signed region, by just inspecting the last
few words of the binary object.
this commits a script that will repeatedly rerun the `btest`
which creates several Bases, fills them with pseudorandom datat,
and goes through a lock/unlock cycle.
should be run with the disk size set to 4MiB for maximum stress
testing (the larger disk won't trigger an FSCB refill because its
hard to run out free space on the larger disk size)
The FPGA gateware region is blocked from trivial readout via USB:
this makes it a tiny bit harder to obtain the gateware image, which
contains the secret keys. This slightly aids users who haven't
burned any efuse keys and are using the default "null" key from
a trivial readout attack, and it also hampers a WBSTAR exploit.
This makes the most convenient path of attack to be loading
a custom xous.img (or otherwise exploiting the kernel) with
a gadget that is capable of reading the gateware region
through priveleged code, and then relaying it over USB through
some run-around of the firewall. This primitive isn't impossible
to create but it doesn't exist and has no use in a normal
operational flow, so, it's going to at least force an attacker
to write some code, as opposed to using off the shelf utilities
we provide.
The `xmas-elf` crate doesn't deal with `raw_data()` of sections that are
`NO_COPY`. These sections may point to data that is outside of the file.
In order to avoid hitting this assert, don't call `raw_data()` on
sections that are marked `NO_COPY`.
Signed-off-by: Sean Cross <sean@xobs.io>
use `usb kbdtest` to output a mapping assuming US-101 maps
it will then derive an appropriate keymap based on that mapping
doesn't support non-ascii characters (yet)
The next release will feature an access control on USB so that
root keys and the encrypted gateware cannot be read back and
transitively the writes would be guttered (but this is not a problem
because the write target address is not set by the memory location
of the write, it's actually set by the location specified in
the program command to the FLASH).
This means that the updating program has to be modified accordingly;
now, for writes, a single location is targeted (and as alluded above,
this is funneled to a write FIFO buffer, and then the actual address is
set with the page program command); and for readback, attempts to read
back the SoC area are flagged and noted as impossible due to security
precautions.
So you'd like to think that an authenticating cipher would like,
authenticate stuff on decryption. And AES-GCM-SIV was billed as sort
of AES with the pointy edges taken off.
Well, there's always one more bug, actually this time a salamander:
https://eprint.iacr.org/2020/1456.pdf Apparently one can forge
authentication if the attacker can control keys and ciphertext. In the
case of the PDDB I think the attack is largely theoretical, because
you'd have to forge through both the AES-GCM-SIV and the rather
insufficient nonce/murmur hash check on the PTE that locates the page
to be decrypted.
But it's never good to have cryptographic properties depend upon
something that's known to be insufficient, so let's assume the attacker
can simply forge keys and stick some data on the device.
This wouldn't be a problem for confidentiality but it could lead to
the ability to plant evidence, but more importantly could lead to code
paths that were thought to be protected against fuzzing being fuzzed
as you could conceivably create a Basis root record that "checked out"
and then the larger body of the PDDB code would try to chomp on other
pages that are forged, leading to a bigger attack surface. Plus who
knows what else might exist beyond salamanders...
This patch does a "key commitment" on the Basis root page, so that it
is now cryptographically hard to create a salamander. Basically
instead of using the system root key directly in AES-GCM-SIV, the key
goes through a KDF that expands it with yet another nonce plus a bit
of header data. The KDF is SHA512/256 and it expands it twice,
changing one bit in the header data (as prescribed by the paper cited
above), to create a version of the key that is written to disk (the
commitment), and a version of the key that is used to
decrypt/authenticate the AES-GCM-SIV data. Only if both the commitment
and the authentication check out, do we accept a Basis root page as
valid.
I had some concerns about the slightly different structure of the
Basis Root page being detectable, but I have been assured that the key
commitment form and the MAC in AES-GCM-SIV satisfy a property known as
IND$-CPA ("indistinguishable from uniform randomness by a
chosen-plaintext attacker") by Rogaway[1], and, more strongly, "Secure
nonce misuse-resistant authenticated encryption (mrAE)" by Gueron and
Lindell (see appendix for def)[2]. Still, just out of total paranoia
and nothing else, I organize the basis root page such that the MAC is
in the identical location as the other non-committed pages...just in
case there is some mathematical property of the MAC that could be
leveraged to leak info about the existence of the basis root record.
The commitment nonce and sha512/256 result I understand better and
feel pretty comfortable that they are going to be strongly random and
indistinguishable from AES ciphertext.
Thanks to Michael Rosenberg for taking the time to explain all this to
me and to guide me through the process of making the fixes. It is a
major PDDB API-breaking change and I'm glad it's able to be rolled out
before most users have received a device.
[1] https://web.cs.ucdavis.edu/~rogaway/papers/ad.pdf
[2] https://eprint.iacr.org/2015/102
the actual transition to a new version isn't here. But,
at the very least, the root keys are now derived by hashing
them MAX_ROLLBACK_LIMIT times, which allows us to create a
key chain based on a global version number that can be incremented
while allowing derviation of older keys without compromising newer
keys.
Each Cargo.toml now includes a comment which remnids maintainers
of the dependency policy for Xous (that is, nail down every dependency
to the minor number).
these are secondary attack surfaces -- code that isn't directly
in the kernel, but involved in the manipulation, handling, grooming
and preparation of source and binary files
Versions are pinned down to the minor number. Yes, this means that
we don't automatically pull in features and bug updates from crates.io,
but it also means we don't pull in new attack surfaces and code that
hasn't been tested or reviewed. I'd like this process to be very deliberate
and not automatic for Xous.
The `rand` crate is almost pinned down to a single version, except
for an odd dependency that's pulled in by hosted mode that depends
on rand 0.8.4 via a subordinate dependency via the `tempfile` crate.
Pondering if it's worth it to try and eliminate that, because the
0.8.4 version doesn't get compiled into any version that touches
real hardware. It just makes it harder to analyze the Cargo.lock
file, mostly. I think I'll leave it as-is.
This is one of the truly redeeming features of Rust is that a
major refactor of a core structure like this doesn't leave me
shaking in my boots -- I feel pretty good that this works
since everything passes the CI tests.
The original FS implementation did the "stupid C thing" which
just creates a fixed lenth field and uses null-terminated C
strings. Which actually restricts PDDB entry names to be ascii
as valid UTF-8 can encode single-byte nulls.
The intention was for names to be fully utf-8 compliant, but in
order to do that we have to burn one byte of potential filename
length and encode an overall length field for the name strings.
This change does that, which both makes the code a bit safer
at the expense of losing a character off of the maximum filename
length.
was mixing deletions and updates and because they are in arbitrary
order due to the hashset structure, sometimes i'd delete an entry
after it was updated.
this is now found and fixed.
should be able to get away with "just" regenerating the fast space
log only if that's what we've run out of; however, doing that optimization
we run into out of space errors. maybe we need some tuning of the thresholds
for when to reclaim space
us to have a full 64-bit address space upon expansion of the page
number (turns out this is probably important because of the crappy
increment-only allocator used for the large blocks)
can create/delete dicts, create/delete/update keys.
basis deletion is...just forgetting the password. that's the point,
at least. could maybe extend the basis AAD to include some small
amount of derived data that could be deleted to facilitate basis
deletion...
anyways. next up is...lots and lots of testing.
this probably isn't new to most other people but this has been
a very visceral exercise of how tricky it is to use Repr(c)
for data layouts in anything but the most trivial data structures.
Unfortunately the Basis root data structure needs to be fairly rich,
so we're playing around with using rkyv to help with the serialization
to disk but I'm also not convinced this is a good idea yet. This
checkpoints commits a "working" rkyv implementation, but I'm not
entirely happy with the notion that rkyv can shuffle around data
bits based on its particular version or decisions in the serializer
crate. I'd like deterministic, repeatable serialization that will
be solid through lots of revs...