/* SPDX-License-Identifier: LicenseRef-Starship-1.0 * Copyright (c) 2023-2026 Robert A. James */ /* test_sk_v4_identity.c -- kernel/src/v4/sk_v4_identity.c on the host (#176): the seeds the identity * code mints and reads while it handles a drive -- genesis, the proxy's login, the real Zuse's -- * are wiped once the drive has been handled, whichever way it went. Drives arrive as on the * machine: a fake xHCI controller marks a slot's drive attach-pending, sk_v4_identity_check_now() * runs the identity code's idle beat, and the drive's GPT is read by the real gpt.c from the * harness's RAM disk. The block layer, the signatures, the key mint, the marker and the console are * faked. */ #define _POSIX_C_SOURCE 200809L #include "harness.h" #include "fakes.h" #include "starkernel/gpt.h" #include "starkernel/xhci_driver.h" #include "starkernel/artemis_sig.h" #include "starkernel/capsule_zuse_boot.h" #include "starkernel/homeblocks_sig.h" #include "starkernel/console.h" #include "starkernel/v4/sk_v4_identity.h" #include "starkernel/v4/sk_v4_marker.h" #include "starkernel/v4/sk_v4_slots.h" #include "block_subsystem.h" #include #include #define SLOTS 4u static xhci_dev_t xdev; static xhci_msc_slot_t ms[SLOTS + 1]; static fake_disk disks[SLOTS + 1]; /* the scenario */ static int sig_blank, key_hers; static sk_v4_marker_t marker_on_stick; static int marker_rc; /* ---- the fakes ---- */ uint32_t xhci_dev_count(void) { return 1u; } xhci_dev_t *xhci_dev_at(uint32_t i) { return i == 0 ? &xdev : 0; } xhci_msc_slot_t *xhci_msc_slot_for(xhci_dev_t *dev, uint32_t slot) { (void)dev; return slot <= SLOTS ? &ms[slot] : 0; } void xhci_poll_events(void) { } int xhci_bringup(xhci_dev_t *dev) { (void)dev; return 0; } int xhci_find_and_map(xhci_dev_t *dev, unsigned index) { (void)dev; (void)index; return -1; } int blkio_usb_open_msc(blkio_dev_t *dev_out, xhci_dev_t *x, uint32_t slot) { (void)x; return fake_disk_bind(dev_out, &disks[slot]) == BLKIO_OK ? 0 : -1; } void *kmalloc_aligned(size_t size, size_t align) { void *p = 0; return posix_memalign(&p, align, size) ? 0 : p; } artemis_sig_result_t artemis_sig_check(struct blkio_dev *dev, artemis_sig_t *out) { (void)dev; memset(out, 0, sizeof *out); return ARTEMIS_SIG_OK; } int blk_subsys_attach_device(struct blkio_dev *dev) { (void)dev; return BLK_OK; } int blk_subsys_detach_device(struct blkio_dev *dev) { (void)dev; return BLK_OK; } int blk_get_device_range(struct blkio_dev *dev, uint32_t *start, uint32_t *count) { (void)dev; *start = 0; *count = 1; return BLK_OK; } int blk_subsys_confirm_format(uint32_t lbn) { (void)lbn; return BLK_OK; } int sk_v4_grow_artemis(blkio_dev_t *art) { (void)art; return 0; } uint64_t sk_v4_grow_cap_sectors(blkio_dev_t *art, uint64_t cap) { (void)art; (void)cap; return 0; } int sk_v4_marker_read(sk_v4_marker_t *m) { *m = marker_on_stick; return marker_on_stick.present ? 0 : -1; } int sk_v4_marker_write(const sk_v4_marker_t *m) { marker_on_stick = *m; return marker_rc; } int sk_v4_mint_zuse(void) { return -1; } homeblocks_sig_result_t homeblocks_sig_check(struct blkio_dev *dev, uint32_t start, homeblocks_sig_t *out) { (void)dev; (void)start; memset(out, 0, sizeof *out); return sig_blank ? HOMEBLOCKS_SIG_BLANK : HOMEBLOCKS_SIG_OK; } int capsule_zuse_boot_genesis_mint(struct blkio_dev *dev, uint8_t seed[32], uint8_t pubkey[32]) { (void)dev; memset(seed, 0x5A, 32); memset(pubkey, 0x11, 32); return 0; } zuse_drive_t capsule_zuse_boot_check_key(struct blkio_dev *dev, homeblocks_sig_result_t rc, const homeblocks_sig_t *sig, const uint8_t want[32], uint8_t seed[32], uint8_t pubkey[32]) { (void)dev; (void)rc; (void)sig; memset(seed, 0x5A, 32); memcpy(pubkey, want, 32); return key_hers ? ZUSE_DRIVE_HERS : (zuse_drive_t)(ZUSE_DRIVE_HERS + 1); } static uint64_t ticks; uint64_t heartbeat_ticks(void) { return ticks += 1000u; } void heartbeat_service(void) { } void apic_timer_start(void) { } void arch_halt(void) { } void arch_enable_interrupts(void) { } int sk_input_getc(void) { return -1; } void sk_input_drop(void) { } void console_cancel_deferred_line_start(void) { } void console_ensure_line_start(void) { } void console_fb_clear(void) { } void console_fb_enable_ttf(void) { } void console_fb_mirror(int on) { (void)on; } void console_set_user_prefix_provider(console_user_prefix_fn fn) { (void)fn; } void console_set_vm_name(const char *name) { (void)name; } uint64_t console_tx_count(void) { return 0; } /* ---- the sticks ---- */ static void put_le32(uint8_t *p, uint32_t v) { p[0] = (uint8_t)v; p[1] = (uint8_t)(v >> 8); p[2] = (uint8_t)(v >> 16); p[3] = (uint8_t)(v >> 24); } static void put_le64(uint8_t *p, uint64_t v) { put_le32(p, (uint32_t)v); put_le32(p + 4, (uint32_t)(v >> 32)); } /* a GPT: the identity partition at 2048..4095, and Artemis after it when `artemis` */ static void make_stick(fake_disk *d, int artemis) { uint64_t sectors = (uint64_t)d->blocks * 2u, last_usable = sectors - 34u; uint8_t *mbr = fake_disk_sector(d, 0), *h = fake_disk_sector(d, 1), *e = fake_disk_sector(d, 2); memset(d->bytes, 0, 34u * 512u); mbr[446 + 4] = 0xEE; put_le32(mbr + 446 + 8, 1u); put_le32(mbr + 446 + 12, (uint32_t)(sectors - 1u)); mbr[510] = 0x55; mbr[511] = 0xAA; memcpy(e, gpt_type_starship_identity, 16); e[16] = 1; put_le64(e + 32, 2048u); put_le64(e + 40, 4095u); if (artemis) { memcpy(e + 128, gpt_type_starship_artemis, 16); e[128 + 16] = 2; put_le64(e + 128 + 32, 4096u); put_le64(e + 128 + 40, 14335u); } memcpy(h, "EFI PART", 8); put_le32(h + 8, 0x00010000u); put_le32(h + 12, 92u); put_le64(h + 24, 1u); put_le64(h + 32, sectors - 1u); put_le64(h + 40, 34u); put_le64(h + 48, last_usable); h[56] = (uint8_t)(0x40 + artemis); put_le64(h + 72, 2u); put_le32(h + 80, 128u); put_le32(h + 84, 128u); put_le32(h + 88, gpt_crc32(e, 128u * 128u)); put_le32(h + 16, 0u); put_le32(h + 16, gpt_crc32(h, 92u)); } static void plug(unsigned slot) { ms[slot].bot_msc_attach_pending = 1; sk_v4_identity_check_now(); } static void pull(unsigned slot) { ms[slot].bot_msc_detach_pending = 1; sk_v4_identity_check_now(); } static int zero(void) { const uint8_t *p = sk_v4_identity_seeds(); unsigned i; for (i = 0; i < 64; i++) if (p[i]) return 0; return 1; } int main(void) { unsigned k; memset(&xdev, 0, sizeof xdev); xdev.max_slots = SLOTS; for (k = 1; k <= SLOTS; k++) fake_disk_open(&(blkio_dev_t){0}, &disks[k], 8192u); make_stick(&disks[1], 1); /* the system stick */ make_stick(&disks[2], 0); /* a real Zuse's stick: identity only */ fake_console_reset(); /* 1. a blank system stick: genesis mints the proxy, and she logs in */ sig_blank = 1; key_hers = 1; marker_rc = 0; memset(&marker_on_stick, 0, sizeof marker_on_stick); plug(1); CHECK(fake_console_said("Zuse: genesis minted onto attached thumbdrive") && sk_v4_identity_present(), "1. genesis: minted, logged in"); CHECK(zero(), "#176: 1. genesis minted -- the seed buffer is zero after"); pull(1); /* 2. genesis whose read-back is not hers: not minted */ memset(&marker_on_stick, 0, sizeof marker_on_stick); key_hers = 0; fake_console_reset(); plug(1); CHECK(fake_console_said("Zuse: genesis mint failed -- not read back") && !sk_v4_identity_present(), "2. genesis not read back: no login"); CHECK(zero(), "#176: 2. genesis not read back -- the seed buffer is zero after"); pull(1); /* 3. the system stick with its proxy Zuse: she logs in */ marker_on_stick.present = 1; memset(marker_on_stick.proxy, 0x11, 32); marker_on_stick.has_real = 0; sig_blank = 0; key_hers = 1; fake_console_reset(); plug(1); CHECK(fake_console_said("Zuse: identity confirmed from attached thumbdrive") && sk_v4_identity_present(), "3. the proxy: logged in"); CHECK(zero(), "#176: 3. the proxy logged in -- the seed buffer is zero after"); pull(1); /* 4. a real Zuse: the system stick in (no session, she exists), then her stick */ marker_on_stick.has_real = 1; memset(marker_on_stick.real, 0x22, 32); fake_console_reset(); plug(1); CHECK(!sk_v4_identity_present(), "4. the system stick, a real Zuse named: the proxy gets no session"); CHECK(zero(), "#176: 4. the proxy's key checked, no session -- the seed buffer is zero after"); plug(2); CHECK(fake_console_said("Zuse: identity confirmed from attached thumbdrive") && sk_v4_identity_present(), "4. her stick: logged in"); CHECK(zero(), "#176: 4. the real Zuse logged in -- the seed buffer is zero after"); return DONE(); }