Files
LithosAnanake/include/starkernel/x509_ed25519.h
T
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

65 lines
3.3 KiB
C

/*
* x509_ed25519.h -- minimal, targeted DER walkers for Ed25519-signed X.509
* certificates (RFC 8410). Deliberately NOT a general ASN.1/X.509 parser
* (Milestone 6 decision, FABRIC-2.md): each function walks exactly as far
* into the DER structure as its own job needs, nothing more.
*
* x509_extract_ed25519_pubkey() only ever reads SubjectPublicKeyInfo --
* no signature verification, no chain validation, no extension parsing.
* That's the capsule-PKI use case (Milestone 6): the embedded snakeoil
* intermediate cert is trusted because it's baked into the trusted build,
* never re-verified against the offline root CA at boot.
*
* x509_verify_signature()/x509_extract_serial() (added 2026-08-28,
* FABRIC-3.md §F.7/§F.17) are for CERTVERIFY -- a regular user's cert,
* which unlike the capsule-PKI chain is signed by Zuse's own on-device
* key and genuinely needs its signature checked at attach time, not just
* trusted by embedding. Two separate trust roots, two separate reasons
* to exist in the same small file (shared DER-walking internals only).
*
* Freestanding C99, no libc beyond memcmp/memcpy (already provided by
* src/starkernel/vm/host/shim.c in the kernel build).
*/
#ifndef STARKERNEL_X509_ED25519_H
#define STARKERNEL_X509_ED25519_H
#include <stdint.h>
#include <stddef.h>
/* Returns 0 on success (pubkey_out[32] filled), -1 on any malformed
* encoding, unexpected structure, or non-Ed25519 algorithm. Never
* faults on malformed input -- every DER length/tag is bounds-checked
* against der_len before use. */
int x509_extract_ed25519_pubkey(const uint8_t *der, size_t der_len,
uint8_t pubkey_out[32]);
/* Verify a DER-encoded certificate's own outer Ed25519 signature (the
* signatureValue field) was produced by issuer_pubkey signing the raw,
* exactly-as-encoded tbsCertificate bytes (DER signs the octets, not a
* re-derived hash of "the fields" -- the TLV framing is part of what's
* signed). Rejects a non-Ed25519 signatureAlgorithm rather than guessing.
*
* Returns 0 if the signature verifies, -1 on any malformed encoding,
* unexpected structure, non-Ed25519 signature algorithm, or a signature
* that does not verify. Never faults on malformed input. */
int x509_verify_signature(const uint8_t *der, size_t der_len,
const uint8_t issuer_pubkey[32]);
/* Extract the raw serialNumber INTEGER content bytes from a DER-encoded
* certificate's tbsCertificate. A single leading 0x00 pad byte (DER adds
* one when the value's high bit would otherwise read as a negative
* INTEGER) is stripped before copying, so a 16-byte drive_uuid compares
* byte-for-byte regardless of whether DER happened to pad it.
*
* @param serial_out Caller-provided buffer.
* @param serial_out_cap Its size in bytes; returns -1 if the real
* (pad-stripped) serial is larger than this.
* @param serial_len_out Set to the real length actually copied.
* @return 0 on success, -1 on any malformed encoding or unexpected
* structure. Never faults on malformed input. */
int x509_extract_serial(const uint8_t *der, size_t der_len,
uint8_t *serial_out, size_t serial_out_cap,
size_t *serial_len_out);
#endif /* STARKERNEL_X509_ED25519_H */