feat(users): keystore v2 (8 slots, per-user salt+name tag, owner admin key opens sealed user dir, per-user duress); gatekeeper login by name+passcode, owner menu (add/remove/guests), passcode change, guest sessions
This commit is contained in:
@@ -18,7 +18,7 @@ use alloc::vec;
|
||||
use keystore::{Block, KdfParams};
|
||||
use libkos::syscall::{self, Received};
|
||||
use types::bounded::CapSlot;
|
||||
use types::gatekeeper::{KEY, SEED, UNLOCK, reply};
|
||||
use types::gatekeeper::{KEY, NAME, REMOVED, SEED, UNLOCK, reply, unlocked};
|
||||
|
||||
/// Where init's manifest put them: its own endpoint (devices arrive on
|
||||
/// it, then init's calls), then the terminal.
|
||||
@@ -67,18 +67,48 @@ pub fn run() -> ! {
|
||||
}
|
||||
drop(memory);
|
||||
match unlocked {
|
||||
Ok(flow::Unlocked { key, fresh }) => {
|
||||
Ok(flow::Unlocked { user, key, fresh, removed }) => {
|
||||
libkos::println!("gatekeeper: unlocked");
|
||||
libkos::terminal::clear(TERMINAL);
|
||||
let words = |b: &[u8; 32]| core::array::from_fn::<usize, 4, _>(|i| usize::from_le_bytes(b[i * 8..i * 8 + 8].try_into().unwrap_or([0; 8])));
|
||||
let mut seed = [0u8; 32];
|
||||
let seeded = keystore::Random::fill(&mut random, &mut seed);
|
||||
if seeded && answer(UNLOCK, [reply::OK, usize::from(fresh), 0, 0]) && answer(KEY, words(&key.0)) {
|
||||
let _ = answer(SEED, words(&seed));
|
||||
} else if !seeded {
|
||||
if !keystore::Random::fill(&mut random, &mut seed) {
|
||||
let _ = answer(UNLOCK, [reply::FAILED, 0, 0, 0]);
|
||||
syscall::exit();
|
||||
}
|
||||
let flags = if fresh { unlocked::FRESH } else { 0 } | if user.is_none() { unlocked::GUEST } else { 0 };
|
||||
let id = user.map_or(0, |u| usize::from_le_bytes(u.id.0));
|
||||
let role = match user.map(|u| u.role) {
|
||||
Some(keystore::Role::Owner) => unlocked::OWNER,
|
||||
Some(keystore::Role::Standard) => unlocked::STANDARD,
|
||||
None => 0,
|
||||
};
|
||||
let mut name_buf = [0u8; 16];
|
||||
let len = match &user {
|
||||
Some(u) => {
|
||||
let n = u.name.as_bytes();
|
||||
name_buf[..n.len()].copy_from_slice(n);
|
||||
n.len()
|
||||
}
|
||||
None => {
|
||||
name_buf[..5].copy_from_slice(b"guest");
|
||||
5
|
||||
}
|
||||
};
|
||||
let name = &name_buf[..len];
|
||||
let handed = answer(UNLOCK, [reply::OK, flags, id, role])
|
||||
&& answer(KEY, words(&key.0))
|
||||
&& answer(SEED, words(&seed))
|
||||
&& answer(NAME, types::log::text_words(name));
|
||||
seed.fill(0);
|
||||
if handed {
|
||||
for gone in removed.iter().flatten() {
|
||||
if !answer(REMOVED, [reply::OK, usize::from_le_bytes(gone.0), 0, 0]) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
let _ = answer(REMOVED, [reply::DONE, 0, 0, 0]);
|
||||
}
|
||||
}
|
||||
Err(why) => {
|
||||
libkos::println!("gatekeeper: cannot go on: {:?}", why);
|
||||
|
||||
Reference in New Issue
Block a user