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
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.