diff --git a/api/openapi.yaml b/api/openapi.yaml index a46eb369..9e88160c 100644 --- a/api/openapi.yaml +++ b/api/openapi.yaml @@ -2513,6 +2513,36 @@ paths: application/json: schema: {$ref: '#/components/schemas/ErrorEnvelope'} + /api/v1/reports/signing-key: + get: + operationId: getReportSigningKey + summary: The public key for verifying report signatures + description: | + Returns the Ed25519 public key (with its key id) used to sign + report snapshots, so a caller can verify a report's signature over + its content_sha256 offline. RBAC: host:read. Spec api-reports. + responses: + '200': + description: The report signing public key + content: + application/json: + schema: {$ref: '#/components/schemas/ReportSigningKey'} + '401': + description: Caller is not authenticated + content: + application/json: + schema: {$ref: '#/components/schemas/ErrorEnvelope'} + '403': + description: Caller lacks host:read permission + content: + application/json: + schema: {$ref: '#/components/schemas/ErrorEnvelope'} + '503': + description: No signer configured + content: + application/json: + schema: {$ref: '#/components/schemas/ErrorEnvelope'} + /api/v1/reports/{id}: get: operationId: getReportByID @@ -5332,7 +5362,7 @@ components: Report: type: object - required: [id, title, kind, scope_label, scope, data_as_of, generated_by, format, content, created_at] + required: [id, title, kind, scope_label, scope, data_as_of, generated_by, format, content, content_sha256, created_at] properties: id: {type: string, format: uuid} title: {type: string} @@ -5352,8 +5382,40 @@ components: compliance_pct, host_count, passing_rules, failing_rules, critical_issues, top_failing_rules, and coverage (hosts_total, hosts_fresh, hosts_stale, hosts_unreachable). + content_sha256: + type: string + description: | + The snapshot's content address: hex SHA-256 of the canonical + content (the json export face reproduces these exact bytes). + signature: + type: string + description: | + Base64 Ed25519 signature over the content address, or absent + for an unsigned snapshot. Verify with the key from + GET /api/v1/reports/signing-key. + signing_key_id: + type: string + description: Fingerprint of the key that produced the signature. created_at: {type: string, format: date-time} + ReportSigningKey: + type: object + required: [key_id, algorithm, public_key, ephemeral] + description: | + The public key used to sign report snapshots, for offline + verification of a report's signature over its content_sha256. + properties: + key_id: {type: string} + algorithm: {type: string, enum: [ed25519]} + public_key: + type: string + description: Base64-encoded Ed25519 public key. + ephemeral: + type: boolean + description: | + True when the server runs a per-boot development key (no durable + key configured); such signatures do not verify across restarts. + ReportListResponse: type: object required: [reports] diff --git a/cmd/openwatch/main.go b/cmd/openwatch/main.go index 186a23ae..0686e874 100644 --- a/cmd/openwatch/main.go +++ b/cmd/openwatch/main.go @@ -630,6 +630,24 @@ func cmdServe(cfg *config.Config, _ []string, stdout, stderr *os.File) int { Sched: complianceSched, }) + // Report signing key. Optional: an empty path yields an ephemeral + // per-boot key (development) so reports still sign; production sets a + // durable key so signatures verify across restarts. + reportSigner, err := report.NewSigner(cfg.Reports.SigningKeyFile) + if err != nil { + slog.ErrorContext(bootCtx, "failed to load report signing key", + slog.String("path", cfg.Reports.SigningKeyFile), + slog.String("error", err.Error())) + return 1 + } + if reportSigner.Ephemeral() { + slog.WarnContext(bootCtx, "report signing key is EPHEMERAL (per-boot) — DEVELOPMENT ONLY; set [reports].signing_key_file (OPENWATCH_REPORTS_SIGNING_KEY_FILE) in production so report signatures verify across restarts", + slog.String("key_id", reportSigner.KeyID())) + } else { + slog.InfoContext(bootCtx, "report signing key loaded", + slog.String("key_id", reportSigner.KeyID())) + } + srv := server.New(cfg, pool). WithConnectivityConfig(cfgStore, liveSvc). WithDiscovery(discoSvc). @@ -651,7 +669,7 @@ func cmdServe(cfg *config.Config, _ []string, stdout, stderr *os.File) int { WithExceptions(exceptionSvc). WithRemediation(remediationSvc). WithGroups(group.NewService(pool)). - WithReports(report.NewService(pool).WithGroups(group.NewService(pool))). + WithReports(report.NewService(pool).WithGroups(group.NewService(pool)).WithSigner(reportSigner)). WithScanResults(scanresult.NewReader(pool)). WithNotifications(notifSvc) runErr := srv.Run(ctx) diff --git a/frontend/src/api/schema.d.ts b/frontend/src/api/schema.d.ts index 70ed47f9..729b8c0a 100644 --- a/frontend/src/api/schema.d.ts +++ b/frontend/src/api/schema.d.ts @@ -1578,6 +1578,28 @@ export interface paths { patch?: never; trace?: never; }; + "/api/v1/reports/signing-key": { + parameters: { + query?: never; + header?: never; + path?: never; + cookie?: never; + }; + /** + * The public key for verifying report signatures + * @description Returns the Ed25519 public key (with its key id) used to sign + * report snapshots, so a caller can verify a report's signature over + * its content_sha256 offline. RBAC: host:read. Spec api-reports. + */ + get: operations["getReportSigningKey"]; + put?: never; + post?: never; + delete?: never; + options?: never; + head?: never; + patch?: never; + trace?: never; + }; "/api/v1/reports/{id}": { parameters: { query?: never; @@ -3549,9 +3571,38 @@ export interface components { content: { [key: string]: unknown; }; + /** + * @description The snapshot's content address: hex SHA-256 of the canonical + * content (the json export face reproduces these exact bytes). + */ + content_sha256: string; + /** + * @description Base64 Ed25519 signature over the content address, or absent + * for an unsigned snapshot. Verify with the key from + * GET /api/v1/reports/signing-key. + */ + signature?: string; + /** @description Fingerprint of the key that produced the signature. */ + signing_key_id?: string; /** Format: date-time */ created_at: string; }; + /** + * @description The public key used to sign report snapshots, for offline + * verification of a report's signature over its content_sha256. + */ + ReportSigningKey: { + key_id: string; + /** @enum {string} */ + algorithm: "ed25519"; + /** @description Base64-encoded Ed25519 public key. */ + public_key: string; + /** + * @description True when the server runs a per-boot development key (no durable + * key configured); such signatures do not verify across restarts. + */ + ephemeral: boolean; + }; ReportListResponse: { reports: components["schemas"]["Report"][]; }; @@ -7551,6 +7602,53 @@ export interface operations { }; }; }; + getReportSigningKey: { + parameters: { + query?: never; + header?: never; + path?: never; + cookie?: never; + }; + requestBody?: never; + responses: { + /** @description The report signing public key */ + 200: { + headers: { + [name: string]: unknown; + }; + content: { + "application/json": components["schemas"]["ReportSigningKey"]; + }; + }; + /** @description Caller is not authenticated */ + 401: { + headers: { + [name: string]: unknown; + }; + content: { + "application/json": components["schemas"]["ErrorEnvelope"]; + }; + }; + /** @description Caller lacks host:read permission */ + 403: { + headers: { + [name: string]: unknown; + }; + content: { + "application/json": components["schemas"]["ErrorEnvelope"]; + }; + }; + /** @description No signer configured */ + 503: { + headers: { + [name: string]: unknown; + }; + content: { + "application/json": components["schemas"]["ErrorEnvelope"]; + }; + }; + }; + }; getReportByID: { parameters: { query?: never; diff --git a/internal/config/config.go b/internal/config/config.go index b052fe8f..080562f2 100644 --- a/internal/config/config.go +++ b/internal/config/config.go @@ -23,6 +23,17 @@ type Config struct { Database DatabaseConfig `toml:"database"` Logging LoggingConfig `toml:"logging"` Identity IdentityConfig `toml:"identity"` + Reports ReportsConfig `toml:"reports"` +} + +// ReportsConfig governs report-snapshot signing. +type ReportsConfig struct { + // SigningKeyFile points at a 32-byte raw Ed25519 seed (mode 0600) + // used to sign report snapshots over their content address. Optional: + // when empty, `openwatch serve` runs with an EPHEMERAL per-boot key + // (development) and logs a warning; production MUST set a durable key + // so signatures verify across restarts. Never stored in the DB. + SigningKeyFile string `toml:"signing_key_file"` } // IdentityConfig holds paths to the at-rest cryptographic material the diff --git a/internal/config/load.go b/internal/config/load.go index 05e0b959..49e333a7 100644 --- a/internal/config/load.go +++ b/internal/config/load.go @@ -110,6 +110,8 @@ var envOverrides = []envOverride{ {"OPENWATCH_IDENTITY_JWT_PRIVATE_KEY", func(c *Config, v string) error { c.Identity.JWTPrivateKey = v; return nil }}, {"OPENWATCH_IDENTITY_CREDENTIAL_KEY_FILE", func(c *Config, v string) error { c.Identity.CredentialKeyFile = v; return nil }}, + + {"OPENWATCH_REPORTS_SIGNING_KEY_FILE", func(c *Config, v string) error { c.Reports.SigningKeyFile = v; return nil }}, } // applyEnv consults each registered env-var; the lookup returns ok=false for diff --git a/internal/report/export.go b/internal/report/export.go index 52099694..54d7beb7 100644 --- a/internal/report/export.go +++ b/internal/report/export.go @@ -41,8 +41,20 @@ func (s *Service) Export(ctx context.Context, id uuid.UUID, face string) ([]byte } switch face { case FaceJSON: - // The canonical snapshot content IS the json face; no caching. - return rep.Content, "application/json", nil + // Canonical content bytes: re-marshal the decoded content so the + // json face reproduces content_sha256 byte-for-byte (the stored + // jsonb column is Postgres-normalized, not identical to the bytes + // that were hashed and signed). This makes the snapshot + // offline-verifiable: sha256(json face) == content_sha256. + var c ExecutiveContent + if err := json.Unmarshal(rep.Content, &c); err != nil { + return nil, "", fmt.Errorf("report: decode content for json face: %w", err) + } + canonical, err := json.Marshal(c) + if err != nil { + return nil, "", fmt.Errorf("report: marshal canonical json: %w", err) + } + return canonical, "application/json", nil case FacePDF: return s.exportPDF(ctx, rep) default: diff --git a/internal/report/export_test.go b/internal/report/export_test.go index 99061657..e6dde13e 100644 --- a/internal/report/export_test.go +++ b/internal/report/export_test.go @@ -11,6 +11,8 @@ package report import ( "bytes" "context" + "crypto/sha256" + "encoding/hex" "errors" "testing" "time" @@ -87,8 +89,11 @@ func TestExport_FacesAndCaching(t *testing.T) { if jsonMedia != "application/json" { t.Errorf("json media = %q", jsonMedia) } - if !bytes.Equal(jsonBody, rep.Content) { - t.Errorf("json face is not the canonical content") + // The json face is canonical: its sha256 reproduces content_sha256, + // so a verifier can confirm the content matches the signed hash. + sum := sha256.Sum256(jsonBody) + if hex.EncodeToString(sum[:]) != rep.ContentSHA256 { + t.Errorf("json face sha256 (%x) != content_sha256 (%s)", sum, rep.ContentSHA256) } // pdf face renders and caches. diff --git a/internal/report/pdf.go b/internal/report/pdf.go index d8679479..b2c571b9 100644 --- a/internal/report/pdf.go +++ b/internal/report/pdf.go @@ -121,8 +121,12 @@ func renderExecutivePDF(rep Report, c ExecutiveContent) ([]byte, error) { if len(short) > 16 { short = short[:16] } - foot := fmt.Sprintf("OpenWatch executive report · content %s… · point-in-time, not signed (MVP) · %s", - short, time.Now().UTC().Format("2006-01-02")) + signed := "not signed" + if len(rep.Signature) > 0 { + signed = "signed " + rep.SigningKeyID + } + foot := fmt.Sprintf("OpenWatch executive report · content %s… · %s · %s", + short, signed, time.Now().UTC().Format("2006-01-02")) pdf.CellFormat(0, 5, tr(foot), "", 0, "L", false, 0, "") var buf bytes.Buffer diff --git a/internal/report/service.go b/internal/report/service.go index 139e0fa0..d04b4591 100644 --- a/internal/report/service.go +++ b/internal/report/service.go @@ -47,6 +47,7 @@ type GroupScoper interface { type Service struct { pool *pgxpool.Pool groups GroupScoper // nil until WithGroups; group scoping then 503s + signer *Signer // nil until WithSigner; snapshots then go unsigned } func NewService(pool *pgxpool.Pool) *Service { @@ -60,16 +61,34 @@ func (s *Service) WithGroups(g GroupScoper) *Service { return s } -const reportCols = `id, title, kind, scope_label, scope, data_as_of, generated_by, format, content, content_sha256, created_at` +// WithSigner wires the Ed25519 signer that signs new snapshots over their +// content address. Without it, snapshots are generated unsigned (signature +// + signing_key_id stay null). +func (s *Service) WithSigner(signer *Signer) *Service { + s.signer = signer + return s +} + +// Signer exposes the wired signer (for the signing-key endpoint), or nil. +func (s *Service) Signer() *Signer { return s.signer } + +const reportCols = `id, title, kind, scope_label, scope, data_as_of, generated_by, format, content, content_sha256, signature, signing_key_id, created_at` func scanReport(row pgx.Row) (Report, error) { var rep Report var scopeRaw []byte + var sig []byte + var keyID *string err := row.Scan(&rep.ID, &rep.Title, &rep.Kind, &rep.ScopeLabel, &scopeRaw, - &rep.DataAsOf, &rep.GeneratedBy, &rep.Format, &rep.Content, &rep.ContentSHA256, &rep.CreatedAt) + &rep.DataAsOf, &rep.GeneratedBy, &rep.Format, &rep.Content, &rep.ContentSHA256, + &sig, &keyID, &rep.CreatedAt) if err != nil { return rep, err } + rep.Signature = sig + if keyID != nil { + rep.SigningKeyID = *keyID + } if len(scopeRaw) > 0 { if err := json.Unmarshal(scopeRaw, &rep.Scope); err != nil { return rep, fmt.Errorf("report: decode scope: %w", err) @@ -121,17 +140,27 @@ func (s *Service) Generate(ctx context.Context, generatedBy string, req Generate } // content_sha256 is the snapshot's content address, computed over the // canonical marshaled content (the exact bytes stored). Identical - // content yields an identical hash - the stable identity A4 will sign. + // content yields an identical hash - the stable identity the signature + // signs over. sum := sha256.Sum256(raw) contentSHA := hex.EncodeToString(sum[:]) + // Sign the content address when a signer is wired. + var signature []byte + var signingKeyID *string + if s.signer != nil { + sig, keyID := s.signer.Sign(contentSHA) + signature = sig + signingKeyID = &keyID + } + dataAsOf := time.Now().UTC() row := s.pool.QueryRow(ctx, ` - INSERT INTO report_snapshots (id, title, kind, scope_label, scope, data_as_of, generated_by, format, content, content_sha256) - VALUES ($1, $2, $3, $4, $5, $6, $7, $8, $9, $10) + INSERT INTO report_snapshots (id, title, kind, scope_label, scope, data_as_of, generated_by, format, content, content_sha256, signature, signing_key_id) + VALUES ($1, $2, $3, $4, $5, $6, $7, $8, $9, $10, $11, $12) RETURNING `+reportCols, uuid.New(), executiveTitle, KindExecutive, scopeLabel(scope), scopeRaw, - dataAsOf, generatedBy, "json", raw, contentSHA) + dataAsOf, generatedBy, "json", raw, contentSHA, signature, signingKeyID) rep, err := scanReport(row) if err != nil { return Report{}, fmt.Errorf("report: generate insert: %w", err) diff --git a/internal/report/signing.go b/internal/report/signing.go new file mode 100644 index 00000000..80cb2275 --- /dev/null +++ b/internal/report/signing.go @@ -0,0 +1,105 @@ +package report + +// Ed25519 signing for report snapshots. A snapshot is signed over its +// content address (content_sha256) with a domain-separated payload, so a +// signature attests "OpenWatch's report key vouches for this exact +// content at generation time" - the tamper-evidence the design calls for. +// Verification is offline: a holder of the public key (served by the +// signing-key endpoint) checks the signature over the same payload, and +// re-hashing the canonical JSON face confirms the content matches the +// signed hash. +// +// Key custody: the private key is a 32-byte raw Ed25519 seed loaded from +// a config path (mode 0600), never stored in the DB - the same custody +// model as the credential key. When no key is configured the signer runs +// EPHEMERAL (a fresh key per boot) for development; production MUST +// provide a durable key so signatures verify across restarts. +// +// Spec: api-reports v1.5.0. + +import ( + "crypto/ed25519" + "crypto/rand" + "crypto/sha256" + "encoding/hex" + "fmt" + "os" +) + +// signingDomain domain-separates the signature so a report signature can +// never be replayed as a signature over some other protocol's bytes. +const signingDomain = "openwatch/report-snapshot/v1\n" + +// Signer signs report snapshots with an Ed25519 key. +type Signer struct { + priv ed25519.PrivateKey + pub ed25519.PublicKey + keyID string + ephemeral bool +} + +// NewSigner builds a Signer. When keyFile is non-empty it loads a 32-byte +// raw Ed25519 seed from that path (mode 0600 expected); when empty it +// generates an ephemeral key for development (Ephemeral() reports true so +// the caller can warn). The key id is a stable fingerprint of the public +// key. +func NewSigner(keyFile string) (*Signer, error) { + if keyFile == "" { + pub, priv, err := ed25519.GenerateKey(rand.Reader) + if err != nil { + return nil, fmt.Errorf("report: generate ephemeral signing key: %w", err) + } + return newSignerFromKeypair(pub, priv, true), nil + } + seed, err := os.ReadFile(keyFile) + if err != nil { + return nil, fmt.Errorf("report: read signing key %s: %w", keyFile, err) + } + if len(seed) != ed25519.SeedSize { + return nil, fmt.Errorf("report: signing key must be %d raw bytes, got %d", ed25519.SeedSize, len(seed)) + } + priv := ed25519.NewKeyFromSeed(seed) + pub := priv.Public().(ed25519.PublicKey) + return newSignerFromKeypair(pub, priv, false), nil +} + +func newSignerFromKeypair(pub ed25519.PublicKey, priv ed25519.PrivateKey, ephemeral bool) *Signer { + return &Signer{priv: priv, pub: pub, keyID: keyIDFor(pub), ephemeral: ephemeral} +} + +// keyIDFor derives a stable, public key id from the public key: the +// hex-encoded first 8 bytes of its SHA-256, prefixed for the algorithm. +func keyIDFor(pub ed25519.PublicKey) string { + sum := sha256.Sum256(pub) + return "ed25519-" + hex.EncodeToString(sum[:8]) +} + +// signingPayload is the domain-separated message actually signed: the +// domain tag followed by the content address. A verifier reconstructs it +// from the published content_sha256. +func signingPayload(contentSHA256 string) []byte { + return append([]byte(signingDomain), []byte(contentSHA256)...) +} + +// Sign returns the Ed25519 signature over the snapshot's content address +// and the key id that produced it. +func (s *Signer) Sign(contentSHA256 string) (sig []byte, keyID string) { + return ed25519.Sign(s.priv, signingPayload(contentSHA256)), s.keyID +} + +// PublicKey returns the verifying key. +func (s *Signer) PublicKey() ed25519.PublicKey { return s.pub } + +// KeyID returns the signer's key id. +func (s *Signer) KeyID() string { return s.keyID } + +// Ephemeral reports whether the signer is a per-boot development key (no +// durable key was configured). +func (s *Signer) Ephemeral() bool { return s.ephemeral } + +// VerifySignature checks an Ed25519 signature over a content address with +// the given public key. Offline-verifiable: callers reconstruct the +// payload from the published content_sha256. +func VerifySignature(pub ed25519.PublicKey, contentSHA256 string, sig []byte) bool { + return ed25519.Verify(pub, signingPayload(contentSHA256), sig) +} diff --git a/internal/report/signing_test.go b/internal/report/signing_test.go new file mode 100644 index 00000000..0064917f --- /dev/null +++ b/internal/report/signing_test.go @@ -0,0 +1,125 @@ +// @spec api-reports +// +// AC-14 TestSigner_SignVerify (Ed25519 sign/verify, key id, ephemeral, seed loading) +// AC-15 TestGenerate_Signed (Generate signs the snapshot; signature verifies; unsigned stays null) + +package report + +import ( + "context" + "crypto/ed25519" + "os" + "path/filepath" + "testing" +) + +// @ac AC-14 +// The signer produces an Ed25519 signature over a content address that +// verifies with its public key; a tampered content address or the wrong +// key fails. An empty key path is ephemeral; a 32-byte seed file loads a +// stable (non-ephemeral) key; a wrong-size seed errors. +func TestSigner_SignVerify(t *testing.T) { + t.Run("api-reports/AC-14", func(t *testing.T) { + s, err := NewSigner("") + if err != nil { + t.Fatalf("NewSigner ephemeral: %v", err) + } + if !s.Ephemeral() { + t.Errorf("empty key path should be ephemeral") + } + sha := "0123456789abcdef0123456789abcdef0123456789abcdef0123456789abcdef" + sig, keyID := s.Sign(sha) + if keyID != s.KeyID() { + t.Errorf("Sign keyID %q != KeyID() %q", keyID, s.KeyID()) + } + if !VerifySignature(s.PublicKey(), sha, sig) { + t.Errorf("valid signature did not verify") + } + // Tampered content address must not verify. + if VerifySignature(s.PublicKey(), sha[:62]+"ff", sig) { + t.Errorf("tampered content verified (should not)") + } + // A different key must not verify. + s2, _ := NewSigner("") + if VerifySignature(s2.PublicKey(), sha, sig) { + t.Errorf("signature verified under the wrong key (should not)") + } + + // A 32-byte seed file loads a stable, non-ephemeral key. + seed := make([]byte, ed25519.SeedSize) + for i := range seed { + seed[i] = byte(i + 1) + } + f := filepath.Join(t.TempDir(), "report-signing.key") + if err := os.WriteFile(f, seed, 0o600); err != nil { + t.Fatal(err) + } + a, err := NewSigner(f) + if err != nil { + t.Fatalf("NewSigner from seed: %v", err) + } + b, _ := NewSigner(f) + if a.Ephemeral() { + t.Errorf("file-loaded signer should not be ephemeral") + } + if a.KeyID() != b.KeyID() { + t.Errorf("same seed gave different key ids: %s vs %s", a.KeyID(), b.KeyID()) + } + // Wrong-size seed errors. + if err := os.WriteFile(f, []byte("too short"), 0o600); err != nil { + t.Fatal(err) + } + if _, err := NewSigner(f); err == nil { + t.Errorf("a wrong-size seed should error") + } + }) +} + +// @ac AC-15 +// Generate with a wired signer stores an Ed25519 signature + key id that +// verifies over the snapshot's content address (and survives a Get +// round-trip); a service with no signer leaves the signature null. +func TestGenerate_Signed(t *testing.T) { + t.Run("api-reports/AC-15", func(t *testing.T) { + pool := freshPool(t) + ctx := context.Background() + signer, _ := NewSigner("") + svc := NewService(pool).WithSigner(signer) + owner := seedUser(t, pool) + h := seedHost(t, pool, owner, false) + seedRuleState(t, pool, h, "r1", "fail", "high") + + rep, err := svc.Generate(ctx, "alice@example.com", GenerateRequest{}) + if err != nil { + t.Fatalf("Generate: %v", err) + } + if len(rep.Signature) == 0 { + t.Fatalf("signed service produced no signature") + } + if rep.SigningKeyID != signer.KeyID() { + t.Errorf("signing_key_id = %q, want %q", rep.SigningKeyID, signer.KeyID()) + } + if !VerifySignature(signer.PublicKey(), rep.ContentSHA256, rep.Signature) { + t.Errorf("stored signature does not verify over content_sha256") + } + + // Get round-trips the signature. + got, err := svc.Get(ctx, rep.ID) + if err != nil { + t.Fatalf("Get: %v", err) + } + if !VerifySignature(signer.PublicKey(), got.ContentSHA256, got.Signature) { + t.Errorf("fetched signature does not verify") + } + + // A service without a signer leaves the signature null. + svc2 := NewService(pool) + rep2, err := svc2.Generate(ctx, "bob@example.com", GenerateRequest{}) + if err != nil { + t.Fatalf("Generate unsigned: %v", err) + } + if len(rep2.Signature) != 0 || rep2.SigningKeyID != "" { + t.Errorf("unsigned service set signature/key: %x / %q", rep2.Signature, rep2.SigningKeyID) + } + }) +} diff --git a/internal/report/types.go b/internal/report/types.go index 6fe08f94..2b071f73 100644 --- a/internal/report/types.go +++ b/internal/report/types.go @@ -42,10 +42,14 @@ type Report struct { Content json.RawMessage // ContentSHA256 is the snapshot's content address: the hex SHA-256 of // the canonical (marshaled) Content. Identical content yields an - // identical hash; it is the stable identity a later signature signs - // over. Not yet exposed on the API wire. + // identical hash; it is the stable identity the signature signs over. ContentSHA256 string - CreatedAt time.Time + // Signature is the Ed25519 signature over the content address (nil + // when the snapshot was generated without a signer). SigningKeyID is + // the fingerprint of the key that produced it. + Signature []byte + SigningKeyID string + CreatedAt time.Time } // Scope is the structured slice of the fleet a report summarizes: an diff --git a/internal/server/api/server.gen.go b/internal/server/api/server.gen.go index b1fd48ab..f8e5a5d3 100644 --- a/internal/server/api/server.gen.go +++ b/internal/server/api/server.gen.go @@ -870,6 +870,21 @@ func (e ReportKind) Valid() bool { } } +// Defines values for ReportSigningKeyAlgorithm. +const ( + Ed25519 ReportSigningKeyAlgorithm = "ed25519" +) + +// Valid indicates whether the value is a known member of the ReportSigningKeyAlgorithm enum. +func (e ReportSigningKeyAlgorithm) Valid() bool { + switch e { + case Ed25519: + return true + default: + return false + } +} + // Defines values for ScanRunQueuedStatus. const ( Queued ScanRunQueuedStatus = "queued" @@ -2614,13 +2629,17 @@ type Report struct { // compliance_pct, host_count, passing_rules, failing_rules, // critical_issues, top_failing_rules, and coverage (hosts_total, // hosts_fresh, hosts_stale, hosts_unreachable). - Content map[string]interface{} `json:"content"` - CreatedAt time.Time `json:"created_at"` - DataAsOf time.Time `json:"data_as_of"` - Format string `json:"format"` - GeneratedBy string `json:"generated_by"` - Id openapi_types.UUID `json:"id"` - Kind ReportKind `json:"kind"` + Content map[string]interface{} `json:"content"` + + // ContentSha256 The snapshot's content address: hex SHA-256 of the canonical + // content (the json export face reproduces these exact bytes). + ContentSha256 string `json:"content_sha256"` + CreatedAt time.Time `json:"created_at"` + DataAsOf time.Time `json:"data_as_of"` + Format string `json:"format"` + GeneratedBy string `json:"generated_by"` + Id openapi_types.UUID `json:"id"` + Kind ReportKind `json:"kind"` // Scope The structured slice of the fleet a report summarizes: an optional // group and/or framework lens. An empty object is the all-hosts, @@ -2628,7 +2647,15 @@ type Report struct { // exactly what a report covers. Scope ReportScope `json:"scope"` ScopeLabel string `json:"scope_label"` - Title string `json:"title"` + + // Signature Base64 Ed25519 signature over the content address, or absent + // for an unsigned snapshot. Verify with the key from + // GET /api/v1/reports/signing-key. + Signature *string `json:"signature,omitempty"` + + // SigningKeyId Fingerprint of the key that produced the signature. + SigningKeyId *string `json:"signing_key_id,omitempty"` + Title string `json:"title"` } // ReportKind defines model for Report.Kind. @@ -2654,6 +2681,23 @@ type ReportScope struct { GroupName *string `json:"group_name,omitempty"` } +// ReportSigningKey The public key used to sign report snapshots, for offline +// verification of a report's signature over its content_sha256. +type ReportSigningKey struct { + Algorithm ReportSigningKeyAlgorithm `json:"algorithm"` + + // Ephemeral True when the server runs a per-boot development key (no durable + // key configured); such signatures do not verify across restarts. + Ephemeral bool `json:"ephemeral"` + KeyId string `json:"key_id"` + + // PublicKey Base64-encoded Ed25519 public key. + PublicKey string `json:"public_key"` +} + +// ReportSigningKeyAlgorithm defines model for ReportSigningKey.Algorithm. +type ReportSigningKeyAlgorithm string + // RoleEntry defines model for RoleEntry. type RoleEntry struct { Description string `json:"description"` @@ -3758,6 +3802,9 @@ type ServerInterface interface { // List generated reports (newest first) // (GET /api/v1/reports) GetReports(w http.ResponseWriter, r *http.Request) + // The public key for verifying report signatures + // (GET /api/v1/reports/signing-key) + GetReportSigningKey(w http.ResponseWriter, r *http.Request) // Fetch one report (with its stored JSON posture) // (GET /api/v1/reports/{id}) GetReportByID(w http.ResponseWriter, r *http.Request, id openapi_types.UUID) @@ -4481,6 +4528,12 @@ func (_ Unimplemented) GetReports(w http.ResponseWriter, r *http.Request) { w.WriteHeader(http.StatusNotImplemented) } +// The public key for verifying report signatures +// (GET /api/v1/reports/signing-key) +func (_ Unimplemented) GetReportSigningKey(w http.ResponseWriter, r *http.Request) { + w.WriteHeader(http.StatusNotImplemented) +} + // Fetch one report (with its stored JSON posture) // (GET /api/v1/reports/{id}) func (_ Unimplemented) GetReportByID(w http.ResponseWriter, r *http.Request, id openapi_types.UUID) { @@ -7908,6 +7961,20 @@ func (siw *ServerInterfaceWrapper) GetReports(w http.ResponseWriter, r *http.Req handler.ServeHTTP(w, r) } +// GetReportSigningKey operation middleware +func (siw *ServerInterfaceWrapper) GetReportSigningKey(w http.ResponseWriter, r *http.Request) { + + handler := http.Handler(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { + siw.Handler.GetReportSigningKey(w, r) + })) + + for _, middleware := range siw.HandlerMiddlewares { + handler = middleware(handler) + } + + handler.ServeHTTP(w, r) +} + // GetReportByID operation middleware func (siw *ServerInterfaceWrapper) GetReportByID(w http.ResponseWriter, r *http.Request) { @@ -9225,6 +9292,9 @@ func HandlerWithOptions(si ServerInterface, options ChiServerOptions) http.Handl r.Group(func(r chi.Router) { r.Get(options.BaseURL+"/api/v1/reports", wrapper.GetReports) }) + r.Group(func(r chi.Router) { + r.Get(options.BaseURL+"/api/v1/reports/signing-key", wrapper.GetReportSigningKey) + }) r.Group(func(r chi.Router) { r.Get(options.BaseURL+"/api/v1/reports/{id}", wrapper.GetReportByID) }) @@ -9369,500 +9439,509 @@ func HandlerWithOptions(si ServerInterface, options ChiServerOptions) http.Handl // const string: with thousands of chunks the chained `+` fold is several // times slower for the Go compiler than parsing a slice literal. var swaggerSpec = []string{ - "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", } // decodeSpec returns the embedded OpenAPI spec as raw JSON bytes, diff --git a/internal/server/api_helpers_test.go b/internal/server/api_helpers_test.go index e6e65b92..0fdcafd7 100644 --- a/internal/server/api_helpers_test.go +++ b/internal/server/api_helpers_test.go @@ -32,6 +32,7 @@ import ( "github.com/Hanalyx/openwatch/internal/liveness" "github.com/Hanalyx/openwatch/internal/notification" "github.com/Hanalyx/openwatch/internal/remediation" + "github.com/Hanalyx/openwatch/internal/report" "github.com/Hanalyx/openwatch/internal/scanresult" "github.com/Hanalyx/openwatch/internal/scheduler" "github.com/Hanalyx/openwatch/internal/secretkey" @@ -302,6 +303,11 @@ func freshAPIServer(t *testing.T) (string, *pgxpool.Pool) { // its sub-routes reach a real handler instead of the 503 not-wired // guard. s.WithGroups(group.NewService(pool)) + // Spec api-reports: wire the reports service with an ephemeral signer + // so /api/v1/reports and /reports/signing-key reach a real handler and + // new snapshots are signed. + reportSigner, _ := report.NewSigner("") + s.WithReports(report.NewService(pool).WithGroups(group.NewService(pool)).WithSigner(reportSigner)) // Spec api-scans: wire the durable per-scan results reader so // /api/v1/scans and its sub-routes reach a real handler. s.WithScanResults(scanresult.NewReader(pool)) diff --git a/internal/server/api_reports_test.go b/internal/server/api_reports_test.go new file mode 100644 index 00000000..5ee7239f --- /dev/null +++ b/internal/server/api_reports_test.go @@ -0,0 +1,87 @@ +// @spec api-reports +// +// AC-16 TestAPI_ReportSigningAndKeyEndpoint — generate a signed report, +// fetch the signing public key, verify the signature offline, and +// confirm the wire exposes content_sha256 + signature + key id. + +package server + +import ( + "crypto/ed25519" + "encoding/base64" + "encoding/json" + "net/http" + "testing" + + "github.com/Hanalyx/openwatch/internal/auth" + "github.com/Hanalyx/openwatch/internal/report" +) + +// @ac AC-16 +func TestAPI_ReportSigningAndKeyEndpoint(t *testing.T) { + t.Run("api-reports/AC-16", func(t *testing.T) { + url, _ := freshAPIServer(t) + + // Generate a report (host:write) — the harness signer signs it. + genReq := asRole(t, "POST", url+"/api/v1/reports:generate", auth.RoleOpsLead, nil) + gr := doReq(t, genReq) + defer gr.Body.Close() + if gr.StatusCode != http.StatusCreated { + t.Fatalf("generate status = %d, want 201", gr.StatusCode) + } + var rep struct { + ID string `json:"id"` + ContentSha256 string `json:"content_sha256"` + Signature string `json:"signature"` + SigningKeyID string `json:"signing_key_id"` + } + if err := json.NewDecoder(gr.Body).Decode(&rep); err != nil { + t.Fatalf("decode report: %v", err) + } + if rep.ContentSha256 == "" || rep.Signature == "" || rep.SigningKeyID == "" { + t.Fatalf("report missing signing fields: %+v", rep) + } + + // Fetch the signing public key (host:read). + keyReq := asRole(t, "GET", url+"/api/v1/reports/signing-key", auth.RoleViewer, nil) + kr := doReq(t, keyReq) + defer kr.Body.Close() + if kr.StatusCode != http.StatusOK { + t.Fatalf("signing-key status = %d, want 200", kr.StatusCode) + } + var key struct { + KeyID string `json:"key_id"` + Algorithm string `json:"algorithm"` + PublicKey string `json:"public_key"` + Ephemeral bool `json:"ephemeral"` + } + if err := json.NewDecoder(kr.Body).Decode(&key); err != nil { + t.Fatalf("decode signing key: %v", err) + } + if key.Algorithm != "ed25519" || key.KeyID != rep.SigningKeyID || !key.Ephemeral { + t.Errorf("signing key = %+v (want ed25519, key id %s, ephemeral)", key, rep.SigningKeyID) + } + + // Offline verification: the report's signature verifies over its + // content address with the published public key. + pub, err := base64.StdEncoding.DecodeString(key.PublicKey) + if err != nil || len(pub) != ed25519.PublicKeySize { + t.Fatalf("bad public key: err=%v len=%d", err, len(pub)) + } + sig, err := base64.StdEncoding.DecodeString(rep.Signature) + if err != nil { + t.Fatalf("bad signature b64: %v", err) + } + if !report.VerifySignature(ed25519.PublicKey(pub), rep.ContentSha256, sig) { + t.Errorf("report signature did not verify with the published public key") + } + + // Anonymous is rejected on the signing-key endpoint. + anon, _ := http.NewRequest("GET", url+"/api/v1/reports/signing-key", nil) + ar, _ := http.DefaultClient.Do(anon) + ar.Body.Close() + if ar.StatusCode != http.StatusUnauthorized && ar.StatusCode != http.StatusForbidden { + t.Errorf("anonymous signing-key status = %d, want 401/403", ar.StatusCode) + } + }) +} diff --git a/internal/server/report_handlers.go b/internal/server/report_handlers.go index 6f399a47..5ed4208a 100644 --- a/internal/server/report_handlers.go +++ b/internal/server/report_handlers.go @@ -13,6 +13,7 @@ package server import ( + "encoding/base64" "encoding/json" "errors" "io" @@ -36,18 +37,28 @@ func toAPIReport(rep report.Report) (api.Report, error) { return api.Report{}, err } } - return api.Report{ - Id: openapitypes.UUID(rep.ID), - Title: rep.Title, - Kind: api.ReportKind(rep.Kind), - ScopeLabel: rep.ScopeLabel, - Scope: toAPIReportScope(rep.Scope), - DataAsOf: rep.DataAsOf, - GeneratedBy: rep.GeneratedBy, - Format: rep.Format, - Content: content, - CreatedAt: rep.CreatedAt, - }, nil + out := api.Report{ + Id: openapitypes.UUID(rep.ID), + Title: rep.Title, + Kind: api.ReportKind(rep.Kind), + ScopeLabel: rep.ScopeLabel, + Scope: toAPIReportScope(rep.Scope), + DataAsOf: rep.DataAsOf, + GeneratedBy: rep.GeneratedBy, + Format: rep.Format, + Content: content, + ContentSha256: rep.ContentSHA256, + CreatedAt: rep.CreatedAt, + } + if len(rep.Signature) > 0 { + sig := base64.StdEncoding.EncodeToString(rep.Signature) + out.Signature = &sig + } + if rep.SigningKeyID != "" { + kid := rep.SigningKeyID + out.SigningKeyId = &kid + } + return out, nil } // toAPIReportScope maps the stored scope to the wire shape, omitting the @@ -118,6 +129,30 @@ func (h *handlers) GetReports(w http.ResponseWriter, r *http.Request) { writeJSON(w, http.StatusOK, resp) } +// GetReportSigningKey implements api.ServerInterface: returns the public +// key for offline verification of report signatures. +// Spec api-reports. +func (h *handlers) GetReportSigningKey(w http.ResponseWriter, r *http.Request) { + if denied := auth.EnforcePermission(w, r, auth.HostRead); denied { + return + } + if !h.reportSvcReady(w) { + return + } + signer := h.reportSvc.Signer() + if signer == nil { + writeError(w, http.StatusServiceUnavailable, "server.unavailable", "server", + "report signing not configured", true) + return + } + writeJSON(w, http.StatusOK, api.ReportSigningKey{ + KeyId: signer.KeyID(), + Algorithm: api.Ed25519, + PublicKey: base64.StdEncoding.EncodeToString(signer.PublicKey()), + Ephemeral: signer.Ephemeral(), + }) +} + // PostReportGenerate implements api.ServerInterface. // Spec api-reports. func (h *handlers) PostReportGenerate(w http.ResponseWriter, r *http.Request) { diff --git a/specs/api/reports.spec.yaml b/specs/api/reports.spec.yaml index ce5a6f09..31a96171 100644 --- a/specs/api/reports.spec.yaml +++ b/specs/api/reports.spec.yaml @@ -1,7 +1,7 @@ spec: id: api-reports title: Reports library - point-in-time Fleet Compliance Executive Summary artifacts (list / generate / fetch) - version: "1.4.0" + version: "1.5.0" status: approved tier: 2 @@ -79,7 +79,7 @@ spec: - The Templates gallery (the six prototype templates beyond the one executive kind) - Retention sweeps (rows are kept; no expiry or purge in the MVP) - Report kinds other than executive (attestation, remediation, exceptions) - - Ed25519 signing - the signature + signing_key_id columns are reserved (nullable, unset) through v1.4.0; signing lands in A4 + - A "Signed" badge / Verify action in the UI (frontend; this spec covers the wire + endpoint) - A period dimension on the scope (applies to the trend) and an explicit host-set scope constraints: @@ -192,11 +192,10 @@ spec: addressing), so two snapshots of an unchanged fleet share a content_sha256 while remaining distinct rows (distinct ids); a posture change changes the hash. content_sha256 is the stable - identity a later Ed25519 signature (A4) signs over; the signature - and signing_key_id columns are reserved (nullable, unset) until - then. The report_faces table is created for later rendered - projections (PDF/CSV/OSCAL) but the executive JSON remains the - canonical snapshot content, not a face row. + identity the Ed25519 signature (C-11) signs over. The report_faces + table is created for later rendered projections (PDF/CSV/OSCAL) but + the executive JSON remains the canonical snapshot content, not a + face row. content_sha256 is exposed on the Report wire. type: technical enforcement: error - id: C-10 @@ -208,8 +207,11 @@ spec: fonts (header + a fixed posture block + the coverage caveat, shown only when some host is stale/unreachable + the small top-failing list) - O(1) pages regardless of fleet size, never the full - per-host/per-rule evidence; format=json returns the canonical - frozen content. The PDF is rendered lazily on first request and + per-host/per-rule evidence; format=json returns the CANONICAL + content (v1.5.0: re-marshaled so its bytes reproduce content_sha256 + byte-for-byte, since the stored jsonb is Postgres-normalized - this + makes the snapshot offline-verifiable, sha256(json face) == + content_sha256). The PDF is rendered lazily on first request and cached in report_faces keyed by (snapshot_id, face) with status 'ready', the byte size, and a blob_sha256 content address; a repeat export re-streams the cached bytes rather than re-rendering. RBAC: @@ -217,6 +219,27 @@ spec: format is 400 reports.invalid_format (report.ErrInvalidFace). type: technical enforcement: error + - id: C-11 + description: >- + v1.5.0 - Report snapshots are Ed25519-signed for tamper-evidence. + When a signer is wired, Generate signs the snapshot's content + address with a domain-separated payload ("openwatch/report-snapshot + /v1\n" + content_sha256) and stores the signature + the signing key + id (a public fingerprint of the key) on the row; the Report wire + exposes signature (base64) + signing_key_id (a service with no + signer leaves them null). The signing key is a 32-byte raw Ed25519 + seed loaded from a config path (never stored in the DB), with an + EPHEMERAL per-boot key when unconfigured (development; the + signing-key endpoint reports ephemeral=true). GET + /api/v1/reports/signing-key (host:read) returns the public key + {key_id, algorithm: ed25519, public_key (base64), ephemeral} so a + holder verifies a report's signature offline: reconstruct the + domain-separated payload from content_sha256 and Ed25519-verify + against the published key; re-hashing the canonical json face + (C-10) confirms the content matches the signed hash. The endpoint is + 503 when no signer is wired. + type: security + enforcement: error acceptance_criteria: - id: AC-01 @@ -342,13 +365,44 @@ spec: references_constraints: [C-10] - id: AC-13 description: >- - v1.4.0 - Export serves the json face as the canonical stored - content (media application/json), and the pdf face as a rendered - application/pdf document. The first pdf export writes a report_faces - row (status 'ready', a 64-char blob_sha256, size_bytes == the byte - length); a second pdf export re-streams the identical cached bytes. - An unknown face returns ErrInvalidFace (handler 400 - reports.invalid_format) and an unknown id returns ErrNotFound - (handler 404). + v1.4.0 - Export serves the json face as CANONICAL content (media + application/json) whose sha256 equals content_sha256 (v1.5.0), and + the pdf face as a rendered application/pdf document. The first pdf + export writes a report_faces row (status 'ready', a 64-char + blob_sha256, size_bytes == the byte length); a second pdf export + re-streams the identical cached bytes. An unknown face returns + ErrInvalidFace (handler 400 reports.invalid_format) and an unknown + id returns ErrNotFound (handler 404). priority: high references_constraints: [C-10] + - id: AC-14 + description: >- + v1.5.0 - The signer signs a content address (Ed25519, domain + separated) and VerifySignature confirms it with the public key; a + tampered content address or the wrong key fails. An empty key path + yields an ephemeral signer (Ephemeral() true); a 32-byte seed file + loads a stable, non-ephemeral key (same seed -> same key id); a + wrong-size seed errors. Pure unit test. + priority: critical + references_constraints: [C-11] + - id: AC-15 + description: >- + v1.5.0 - Generate with a wired signer stores an Ed25519 signature + + signing_key_id that verify over the snapshot's content_sha256 (and + survive a Get round-trip); a service with no signer leaves signature + and signing_key_id null. + priority: critical + references_constraints: [C-11] + - id: AC-16 + description: >- + v1.5.0 - End to end over the API: POST /reports:generate (host:write) + returns a report whose wire carries content_sha256, signature + (base64), and signing_key_id. GET /api/v1/reports/signing-key + (host:read) returns {key_id == the report's signing_key_id, + algorithm "ed25519", public_key (base64), ephemeral true under the + test's per-boot key}; decoding the public key and the signature and + reconstructing the domain-separated payload from content_sha256 + Ed25519-verifies the report's signature. An anonymous caller is + rejected (401/403) on the signing-key endpoint. + priority: high + references_constraints: [C-11]