/** * OBJECTIVE ORACLE (INV4/INV14) — proves the control-plane's REAL leaf issuer emits an X.509 leaf * that relay-auth's `verifyAgentCert` accepts, WITHOUT deploying either service. * * A throwaway Ed25519 root→intermediate chain is generated in-test; a leaf is issued through * `createRealLeafSigner` for a random account/host + agent pubkey; then relay-auth verifies the * leaf against the intermediate+root bundle with a fake host registry. Positive path asserts * `{ ok: true, hostId, accountId }`; negatives assert the exact reject reasons. */ import 'reflect-metadata' import { describe, test, expect } from 'vitest' import * as x509 from '@peculiar/x509' import { webcrypto, randomUUID } from 'node:crypto' import { verifyAgentCert, defaultParseX509 } from 'relay-auth/src/agent/verify-mtls.js' import { spiffeIdFor } from 'relay-auth/src/agent/spiffe.js' import type { HostRecord } from 'relay-contracts' import { createMemoryStores } from '../src/store/memory.js' import { createHostRegistry } from '../src/registry/hosts.js' import { createRealLeafSigner, loadRealLeafSigner } from '../src/ca/issue.js' import { buildCsr } from '../src/ca/csr.js' import { fingerprint } from '../src/ca/fingerprint.js' import { generateEd25519 } from '../src/util/crypto.js' x509.cryptoProvider.set(webcrypto) const TRUST_DOMAIN = 'example.com' const DAY_MS = 24 * 60 * 60 * 1000 interface Ca { readonly intKey: CryptoKey readonly issuerName: x509.Name readonly caChainDer: readonly Uint8Array[] readonly caChainPem: string readonly intermediateKeyPem: string readonly intermediateCertPem: string readonly rootCertPem: string } type KeyPair = { readonly publicKey: CryptoKey; readonly privateKey: CryptoKey } function derToPemLabeled(der: Uint8Array, label: string): string { const b64 = Buffer.from(der).toString('base64').match(/.{1,64}/g)?.join('\n') ?? '' return `-----BEGIN ${label}-----\n${b64}\n-----END ${label}-----\n` } async function makeCa(): Promise { const subtle = webcrypto.subtle const rootKeys = (await subtle.generateKey({ name: 'Ed25519' }, true, ['sign', 'verify'])) as unknown as KeyPair const intKeys = (await subtle.generateKey({ name: 'Ed25519' }, true, ['sign', 'verify'])) as unknown as KeyPair const now = Date.now() const rootCert = await x509.X509CertificateGenerator.createSelfSigned({ serialNumber: '01', name: 'CN=relay-root', notBefore: new Date(now - DAY_MS), notAfter: new Date(now + DAY_MS), keys: rootKeys, signingAlgorithm: { name: 'Ed25519' }, extensions: [new x509.BasicConstraintsExtension(true, undefined, true)], }) const intCert = await x509.X509CertificateGenerator.create({ serialNumber: '02', subject: 'CN=relay-intermediate', issuer: rootCert.subjectName, notBefore: new Date(now - DAY_MS), notAfter: new Date(now + DAY_MS), publicKey: intKeys.publicKey, signingKey: rootKeys.privateKey, signingAlgorithm: { name: 'Ed25519' }, extensions: [new x509.BasicConstraintsExtension(true, undefined, true)], }) const intKeyPkcs8 = new Uint8Array(await subtle.exportKey('pkcs8', intKeys.privateKey)) return { intKey: intKeys.privateKey, issuerName: intCert.subjectName, caChainDer: [new Uint8Array(intCert.rawData), new Uint8Array(rootCert.rawData)], caChainPem: `${intCert.toString('pem')}\n${rootCert.toString('pem')}`, intermediateKeyPem: derToPemLabeled(intKeyPkcs8, 'PRIVATE KEY'), intermediateCertPem: intCert.toString('pem'), rootCertPem: rootCert.toString('pem'), } } function derToPem(der: Uint8Array): string { return new x509.X509Certificate(der).toString('pem') } /** Minimal relay-contracts HostRecord for the fake registry (only accountId/status are read). */ function fakeHost(hostId: string, accountId: string, status: HostRecord['status']): HostRecord { return { hostId, accountId, subdomain: 'host', agentPubkey: new Uint8Array(32), enrollFpr: 'fpr', status, lastSeen: new Date().toISOString(), createdAt: new Date().toISOString(), revokedAt: status === 'revoked' ? new Date().toISOString() : null, } as HostRecord } async function issueLeaf() { const ca = await makeCa() const stores = createMemoryStores() const hosts = createHostRegistry({ hosts: stores.hosts }) const accountId = randomUUID() const { publicKeyRaw, privateKey } = generateEd25519() const host = await hosts.bindHost({ accountId, subdomain: 'alice', agentPubkey: publicKeyRaw, enrollFpr: fingerprint(publicKeyRaw), }) const signer = createRealLeafSigner({ hosts: stores.hosts, intermediateKey: ca.intKey, issuerName: ca.issuerName, caChainDer: ca.caChainDer, trustDomain: TRUST_DOMAIN, }) const { cert, caChain } = await signer.signHostLeaf(host.hostId, publicKeyRaw, buildCsr(privateKey, publicKeyRaw)) return { ca, accountId, hostId: host.hostId, publicKeyRaw, leafPem: derToPem(cert), caChain } } describe('interop: control-plane real leaf ⇄ relay-auth verifyAgentCert', () => { test('valid leaf for an active enrolled host → { ok: true, hostId, accountId }', async () => { const { ca, accountId, hostId, leafPem, caChain } = await issueLeaf() expect(caChain).toHaveLength(2) // intermediate + root DER const registry = { getById: async (id: string) => (id === hostId ? fakeHost(hostId, accountId, 'online') : null) } const res = await verifyAgentCert(leafPem, ca.caChainPem, Math.floor(Date.now() / 1000), registry, defaultParseX509) expect(res).toEqual({ ok: true, hostId, accountId }) }) test('SPIFFE accountId ≠ registry accountId → spiffe_account_mismatch', async () => { const { ca, hostId, leafPem } = await issueLeaf() const registry = { getById: async (id: string) => (id === hostId ? fakeHost(hostId, randomUUID(), 'online') : null) } const res = await verifyAgentCert(leafPem, ca.caChainPem, Math.floor(Date.now() / 1000), registry, defaultParseX509) expect(res.ok).toBe(false) expect(res.reason).toBe('spiffe_account_mismatch') }) test('revoked host → host_revoked', async () => { const { ca, accountId, hostId, leafPem } = await issueLeaf() const registry = { getById: async (id: string) => (id === hostId ? fakeHost(hostId, accountId, 'revoked') : null) } const res = await verifyAgentCert(leafPem, ca.caChainPem, Math.floor(Date.now() / 1000), registry, defaultParseX509) expect(res.ok).toBe(false) expect(res.reason).toBe('host_revoked') }) test('expired leaf → expired', async () => { const ca = await makeCa() const accountId = randomUUID() const hostId = randomUUID() const { publicKeyRaw } = generateEd25519() const spiffe = spiffeIdFor(accountId, hostId, TRUST_DOMAIN) const prefix = Uint8Array.from([0x30, 0x2a, 0x30, 0x05, 0x06, 0x03, 0x2b, 0x65, 0x70, 0x03, 0x21, 0x00]) const spki = new Uint8Array(44) spki.set(prefix, 0) spki.set(publicKeyRaw, 12) const subjectKey = await webcrypto.subtle.importKey('spki', spki, { name: 'Ed25519' }, true, ['verify']) const now = Date.now() const expiredLeaf = await x509.X509CertificateGenerator.create({ serialNumber: '0e', subject: `CN=${hostId}`, issuer: ca.issuerName, notBefore: new Date(now - 2 * DAY_MS), notAfter: new Date(now - DAY_MS), // already expired publicKey: subjectKey, signingKey: ca.intKey, signingAlgorithm: { name: 'Ed25519' }, extensions: [new x509.SubjectAlternativeNameExtension([{ type: 'url', value: spiffe }])], }) const registry = { getById: async (id: string) => (id === hostId ? fakeHost(hostId, accountId, 'online') : null) } const res = await verifyAgentCert( expiredLeaf.toString('pem'), ca.caChainPem, Math.floor(Date.now() / 1000), registry, defaultParseX509, ) expect(res.ok).toBe(false) expect(res.reason).toBe('expired') }) test('boot path: loadRealLeafSigner (PEM material) issues a verifiable leaf', async () => { const ca = await makeCa() const stores = createMemoryStores() const hosts = createHostRegistry({ hosts: stores.hosts }) const accountId = randomUUID() const { publicKeyRaw, privateKey } = generateEd25519() const host = await hosts.bindHost({ accountId, subdomain: 'boot', agentPubkey: publicKeyRaw, enrollFpr: fingerprint(publicKeyRaw), }) const signer = await loadRealLeafSigner({ hosts: stores.hosts, intermediateKeyPem: ca.intermediateKeyPem, intermediateCertPem: ca.intermediateCertPem, rootCertPem: ca.rootCertPem, trustDomain: TRUST_DOMAIN, }) const { cert } = await signer.signHostLeaf(host.hostId, publicKeyRaw, buildCsr(privateKey, publicKeyRaw)) const registry = { getById: async (id: string) => (id === host.hostId ? fakeHost(host.hostId, accountId, 'online') : null), } const res = await verifyAgentCert(derToPem(cert), ca.caChainPem, Math.floor(Date.now() / 1000), registry, defaultParseX509) expect(res).toEqual({ ok: true, hostId: host.hostId, accountId }) }) test('intermediate-only bundle (no root) → chain_invalid', async () => { const { ca, accountId, hostId, leafPem } = await issueLeaf() const intermediateOnly = ca.caChainPem.split('-----END CERTIFICATE-----')[0]! + '-----END CERTIFICATE-----\n' const registry = { getById: async (id: string) => (id === hostId ? fakeHost(hostId, accountId, 'online') : null) } const res = await verifyAgentCert(leafPem, intermediateOnly, Math.floor(Date.now() / 1000), registry, defaultParseX509) expect(res.ok).toBe(false) expect(res.reason).toBe('chain_invalid') }) })