In general, hosted mode is assumed "by default" if the target
is not Xous. This allows packages to be built cleanly on command
lines that don't know to pass a --feature flag to specify a target.
However, an explicit "hosted" flag is still retained so that we
can confirm the build system intent. This saves us from the failure
mode that we thought we were building for target A, but accidentally
ommitted the flag, and instead we've been silently building for
"hosted" mode without any warning. The main consumer of the "hosted"
flag is now just the build.rs script inside of the utralib.
Because we unmount the PDDB and put the system in a semi-shutdown
state, backups are not abortable if you type in the wrong root password.
This patch retries the root password forever, but also adds a note
at the beginning of the process that the process cannot be stopped
once started.
rkyv-derived enums throw warnings that they are unused.
Not sure how to get rid of them; I've tried surrounding them in
`#[allow(dead_code)]` directives, and also explicitly creating
each enum variant that I'm aware of through some dummy code and
some log prints of the dummy code calls to ensure the results are
used, and the warnings still persist.
Significantly, the warnings only happen for enums that take
a value. Simple rkyv enums do not throw a warning.
These warnings overwhelm the build logs, so they need to be isolated
in order for us to ensure that the build is clean of other more
important warnings.
The method chosen to isolate them is to take the enums that are
problematic, carve them into their own special file, and add
a file-wide `#![allow(dead_code)]` directive. This only happens
in 7 service crates, and this change commits all of the modifications
in a single big commit that could be undone later if this turns out
to be a compiler regression or something similar.
I also opened an issue with the rkyv maintainer to see what his
opinion is on the situation.
https://github.com/rkyv/rkyv/issues/318
every 1MiB block is checksummed with a sha512/256 truncated to
128 bits. This is used to confirm the media and transport integrity
only. It is not intended to be a cryptographic check, it just confirms
that the backup data was transferred correctly assuming no intentionally
malicious actors in the middle.
This will allow for e.g. xous on riscv32-imac but not a precursor
target, for example: by using feature selectors we get to have
a bigger range of targets that we support, such as for implementations
that haven't been upstreamed or have official target-triples.
The downsides are:
- patch override libraries don't absorb feature flags. so, for
example, the AES crate that is used to patch other crates won't
be aware of the target features without modifying the referencing
crates.
- features are normally meant to be additive, but target features
are mutually exclusive. The mutex is enforced by a check in
utralib that throws a panic on build if two targets are accidentally
selected at the same time.
- boot PIN is not requested on root password init. it's redundant,
as it is actually set when you format the PDDB
- boot key was mistakenly a copy of the encrypted private key
for ed25519 key signing. "oops". didn't catch that bug until now...
i don't think it has a big impact on existing user base, because
the key is never exposed outside the rootkey server, and the
ed25519 key itself is encrypted with the root password and then
used as the boot key. But still -- that's just not what was intended.
- root password is requested twice to check the validity of the password
this patch moves us off the branch we had to hop on for cipher
API compatibility to the one that's officially published by
RustCrypto. This closes#168.
The crate we originally grabbed for AES-KWP seems to be non-compliant
(or I'm an idiot and I can't figure out how to call it in a way
that is compliant).
See https://github.com/jedisct1/rust-aes-keywrap/issues/9
Turns out that `aes_kw` *is* compliant, but unfortunately, it didn't
exist back when the PDDB was being written. The PDDB started in October
2021, and `aes_kw` was pushed in Jan 2022. *just* barely missed it.
Anyways, caught this error while trying to implement some CI for
backups. Hurray for testing!
This patch removes the encryption path using the incorrect version
of the algorithm, but leaves the decryption path in place. The
system will try to decrypt initially with the correct version,
but if that fails, it will fall back and try the incorrect version.
If that succeeds, it returns an error code with the correct key and
an updated wrapped key, which the caller can store so that future
calls do not fail. Thus, we have a seamless migration from the
incorrect version to the correct version.
Have verified that the aes_kw version *does* work with the CI
script, insofar as it has been written (we just got to that point
and got stuck). So, full speed ahead. Users shouldn't notice this
change.
Also, fwiw, I did take a look at the "incorrect" implementation,
and it doesn't look obviously insecure. Printing out the various
rounds of the wrapping function looks like the first couple rounds
match, but it diverges somewhere probably due to an off-by-one
in a counter or something like that. I didn't chase it out -- just
wanted to make sure that nothing looked like a huge data compromise.
Good news is this comes right on the heels of v0.9.9 release, so
this will be pushed as a hotfix right away.
this facility is necessary in case a worker accidentally picks
the wrong setting, disabling the feature for the device. When
the factory test completes, a call is made to reset the parameter.
This was a slightly complicated affair because the the don't ask
flag is contained within the rootkeys enclave itself, and we can't
just give access to rootkeys willy-nilly. So the flag is passed
through the PDDB and then to the rootkeys enclave. It's not harmful
to have it reset by an unauthorized actor; the pop-up will not
happen if passwords are, in fact, already set.
verification happens after the private key material is erased,
which incidentally nukes public key material, causing verification
to fail. This caches a copy of the pubkey material before
the erase happens.
- read order of keys was wrong from staged data
- make restore a blocking op so the Ux doesn't try to trigger
other things at boot
- fix pubkey check to use staged key for backup flow
- fix some wording and skip redundant messages
Just remembered that the PDDB is *locked* to a given device.
To restore to a new device, you have to unlock all the Bases,
and re-encrypt them to the new device's DNA.
This commit adds the facilities to detect this condition, but
the actual code to do this is quite involved...let's handle that
after we've got a "simple" restore to the same device going.
Why do we lock to a device's DNA? the idea is to prevent
attacks where people are taking static blocks of crypto data
and just swapping it between devices to see if they can
get something to decrypt. It also makes it harder for
an adversary to replace the physical device -- e.g., an
evil maid prepared a replacement with implants in advance, and they
image your PDDB onto the replaced device, hoping that you don't
notice. Because the PDDB is device-locked, the "evil maid"
would have to forge the devices DNA to match yours:
possible, but would require kernel mods that patch over the
reported ID; that would trigger the line across the top of the
screen; or, somehow editing the FPGA itself to force
its device ID to report the same as yours. This last attack
vector would be successful, but afaik there is no known way
to modify an FPGA's DNA code. I'm sure there is some proprietary
secret know that Xilinx uses to set it, and if you were
a large government you may be able to coerce Xilinx into giving
you those codes plus some tool that could set the fuses
plus some unfused devices (the fuses are burn-once) but....
- do not try to create root keys if we just did an SoC update.
that's just too many things going on, we should definitely force
a clean reboot first.
- add a clean reboot step after a no-key soc update
- try to switch USB debug mode on if a backup was created