Files
Robert Allan JamesandClaude Sonnet 5 0ec91b517a Implement CERTVERIFY -- real DER cert verification, tested against OpenSSL
Phase B of the identity pipeline (FABRIC-3.md §F.7/§F.17):

- x509_ed25519.c/.h: two new DER walkers alongside the existing pubkey
  extractor -- x509_verify_signature() (verifies a cert's outer Ed25519
  signature over the raw, exactly-as-encoded tbsCertificate bytes, real
  signature verification against issuer_pubkey, rejects non-Ed25519
  signatureAlgorithm) and x509_extract_serial() (extracts the
  serialNumber INTEGER, stripping a DER padding byte if present, for the
  drive_uuid binding decided in §F.7).

- vm_identity.c: vm_identity_from_cert(), ties the three DER primitives
  together into the actual CERTVERIFY check -- signature verifies against
  issuer_pubkey, serialNumber matches this drive's own drive_uuid,
  subject pubkey extracts cleanly -- and populates a VMIdentity on
  success. acl_caps is caller-supplied, not read from the cert (nothing
  in the decided cert fields encodes capabilities); deciding what a
  verified identity is allowed to do is policy for the caller (WIREBIND,
  not yet built), not this function's job.

Verified two ways: a standalone host-side test harness (not part of the
kernel build) links the real source files against a real openssl-
generated Ed25519 X.509 cert -- extracted pubkey, extracted serial, and
signature verification all match ground truth, plus two negative tests
(wrong issuer pubkey, corrupted signature) both correctly rejected. Then
the actual kernel build verified live on all three architectures: clean
compile, clean boot to ok>, Hermes/Artemis both live with no KILL. Same
pre-existing, unrelated Zuse fence-write anomaly observed on all three
(not caused by this change, not chased here).

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_019ZGkimpfyh63EZyRkNbkPD
2026-08-28 09:38:18 -04:00

126 lines
5.8 KiB
C
Raw Permalink Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
/*
StarForth — Steady-State Virtual Machine Runtime
Copyright (c) 20232025 Robert A. James
All rights reserved.
This file is part of the StarForth project.
Licensed under the StarForth License, Version 1.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at:
https://github.com/star.4th@proton.me/StarForth/LICENSE.txt
This software is provided "AS IS", WITHOUT WARRANTY OF ANY KIND,
express or implied, including but not limited to the warranties of
merchantability, fitness for a particular purpose, and noninfringement.
See the License for the specific language governing permissions and
limitations under the License.
*/
/**
* vm_identity.h - Per-VM owner identity + ACL capabilities (FABRIC-3.md
* §F.2/§F.16, decided 2026-08-27/28)
*
* Holds only what a VM needs to prove *who owns it* and *what that owner
* is allowed to do* -- never a private key. A regular VM's lock never
* signs anything itself, so no seed/private material belongs here at all
* (unlike Zuse's own zuse_cert_seed/zuse_cert_pubkey pair, which does need
* one because she actively signs). Deliberately its own header rather
* than inline fields on struct VM, mirroring VMUuid's own precedent
* (vm_uuid.h) -- standing instruction: give real-shaped data its own
* header and integrate as a field, don't grow struct VM ad hoc.
*
* acl_caps is a capability bitmask, not an ordered privilege tier
* (decided 2026-08-28) -- independent bits, not a nested hierarchy. Zuse
* is not a structurally special VM: her identity just has every bit set.
* No bit values are assigned yet -- deliberate slack, per this project's
* "flexibility until we understand the recipe" precedent (see
* blk_meta_t's own acl_reserved bytes, FABRIC-3.md §F.4) -- real bits get
* names only once the operation they gate actually gets built (BINDSTEP,
* MINT, ...), not speculatively here.
*/
#ifndef STARKERNEL_VM_IDENTITY_H
#define STARKERNEL_VM_IDENTITY_H
#ifdef __STARKERNEL__
#include <stdint.h>
#include <stddef.h>
typedef struct {
uint8_t owner_pubkey[32]; /**< Ed25519 public key of this VM's owning
* identity. Meaningless unless installed
* is set. */
uint8_t installed; /**< 0 = no identity installed yet (e.g.
* Hera/Hermes/Artemis today, before
* D.5's per-VM-identity work lands) --
* BINDSTEP-style checks must treat this
* as "no lock, allow freely," matching
* §F.9 decision 2. 1 = owner_pubkey/
* acl_caps are real. */
uint32_t acl_caps; /**< Capability bitmask. All-zero until a
* real caller defines and checks a bit;
* VM_IDENTITY_CAP_ALL for Zuse's own
* identity ("her ACL just grants
* everything," not a special VM type). */
} VMIdentity;
/** Every capability bit set -- Zuse's own identity uses this, not a
* distinct "is this Zuse" flag anywhere else in the system. */
#define VM_IDENTITY_CAP_ALL 0xFFFFFFFFu
/**
* vm_identity_has_cap - Check whether an installed identity holds a
* capability. Returns 0 (denied) if identity isn't installed at all --
* callers that mean "no lock, allow freely" (§F.9 decision 2) must check
* installed themselves first, not call this and treat 0 as a denial in
* that case.
*
* @param id Identity to check.
* @param cap A single capability bit (or bits) to test for.
* @return Non-zero if id is installed and every bit in cap is set.
*/
int vm_identity_has_cap(const VMIdentity *id, uint32_t cap);
/**
* vm_identity_from_cert - CERTVERIFY (FABRIC-3.md §F.7/§F.17): verify a
* DER-encoded, Zuse-signed X.509 cert and populate a VMIdentity from it.
*
* Three checks, all must pass: the cert's own signature verifies against
* issuer_pubkey (Zuse's own on-device key -- a separate trust root from
* the capsule-PKI chain, no chain walk needed); the cert's serialNumber
* equals drive_uuid byte-for-byte (binds this cert to one physical drive,
* §F.7 decision 2 -- a copied cert on different media will not verify);
* the subject's Ed25519 public key extracts cleanly.
*
* acl_caps is *not* read from the cert -- nothing in the decided cert
* fields encodes capabilities (§F.16). It's supplied by the caller, whose
* job it is to decide what this verified identity is allowed to do (e.g.
* comparing the extracted pubkey against Zuse's own system-resident
* pubkey to decide VM_IDENTITY_CAP_ALL vs. a lesser default) -- that
* policy decision doesn't belong inside a pure verification function.
*
* @param out Populated on success; left untouched on failure.
* @param der DER-encoded certificate bytes.
* @param der_len Their length.
* @param issuer_pubkey Zuse's own Ed25519 public key.
* @param drive_uuid This physical drive's own 16-byte drive_uuid
* (homeblocks_sig_t), compared against the cert's
* serialNumber.
* @param acl_caps Capability bitmask to install, caller-decided.
* @return 0 on success, -1 if any check fails (malformed DER, wrong
* signature algorithm, signature doesn't verify, serial mismatch,
* or the extracted key isn't a valid Ed25519 point).
*/
int vm_identity_from_cert(VMIdentity *out, const uint8_t *der, size_t der_len,
const uint8_t issuer_pubkey[32],
const uint8_t drive_uuid[16], uint32_t acl_caps);
#endif /* __STARKERNEL__ */
#endif /* STARKERNEL_VM_IDENTITY_H */