Watch
1
0
Fork
You've already forked RedFlag
0
RedFlag/RAF/verification/02-agent-verification.md
Fimeg d9ba008f67 raf: sync docs to code + relative cross-reference links
Handler/migration counts, calculateBackoff -> calculateDelay, machine-id
binding (cross-platform machineid + fallbacks, not hostname), last-reviewed
dates, and made [[cross-references]] relative so they resolve.
2026-06-15 09:39:34 -04:00

4.8 KiB

Agent-Side Verification

Agent verifies commands and binaries before execution.


Overview

Agent verifies Ed25519 signatures, timestamps, and nonces before executing commands.

Cross-references:


Public Key Caching (TOFU)

Method: Trust On First Use — TTL+key_id cache with rotation awareness

File: agent/internal/crypto/pubkey.go

func FetchAndCacheServerPublicKey(serverURL string) (ed25519.PublicKey, error) {
    // 1. Check if cache is valid (TTL + key_id match)
    if meta, err := loadCacheMetadata(); err == nil && meta.KeyID != "" && !meta.IsExpired() {
        if cachedKey, loadErr := LoadCachedPublicKey(); loadErr == nil {
            return cachedKey, nil
        }
    }

    // 2. Fetch from server GET /api/v1/public-key
    pubKeyBytes, err := httpGetPublicKey(serverURL)
    if err != nil {
        return nil, fmt.Errorf("failed to fetch public key: %w", err)
    }

    // 3. Cache to disk
    if err := cachePublicKey(pubKeyBytes); err != nil {
        fmt.Printf("Warning: Failed to cache public key: %v\n", err)
    }

    return pubKeyBytes, nil
}

Command Verification

Method: Verify v3 signature with timestamp, falls back to older formats for backward compatibility

File: agent/internal/crypto/verification.go

func (v *CommandVerifier) VerifyCommandWithTimestamp(
    cmd client.Command,
    serverPubKey ed25519.PublicKey,
    maxAge time.Duration,
    clockSkew time.Duration,
) error {
    // 1. If cmd.SignedAt is nil, fall back to oldest format (backward compat)
    if cmd.SignedAt == nil {
        fmt.Printf("[WARNING] [agent] [crypto] command_uses_oldest_format command_id=%s no_signed_at=true upgrade_server_recommended\n", cmd.ID)
        return v.VerifyCommand(cmd, serverPubKey)
    }

    // 2. Validate timestamp window
    now := time.Now().UTC()
    age := now.Sub(*cmd.SignedAt)
    if age > maxAge {
        return fmt.Errorf("command timestamp too old: signed %v ago (max %v)", age.Round(time.Second), maxAge)
    }
    if age < -clockSkew {
        return fmt.Errorf("command timestamp is in the future: %v ahead (max skew %v)", (-age).Round(time.Second), clockSkew)
    }

    // 3. Try v3 format first (with agent_id) if AgentID is present
    if cmd.AgentID != "" {
        message, err := v.reconstructMessageV3(cmd)
        if err != nil {
            return fmt.Errorf("failed to reconstruct v3 message: %w", err)
        }
        if ed25519.Verify(serverPubKey, message, sig) {
            return nil // v3 verification succeeded
        }
        // v3 failed — try v2 as fallback
    }

    // 4. v2 format: timestamp but no agent_id (backward compat)
    message, err := v.reconstructMessageWithTimestamp(cmd)
    if err != nil {
        return fmt.Errorf("failed to reconstruct timestamped message: %w", err)
    }
    if !ed25519.Verify(serverPubKey, message, sig) {
        return errors.New("signature verification failed")
    }
    return nil
}

Verification Modes:

  • Strict: Reject all verification failures (default)
  • Warning: Log failure but execute command
  • Disabled: Skip verification entirely

Fallback Chain: v3 (agent_id + timestamp) → v2 (timestamp only) → oldest (no timestamp)


**Verification Modes:**
- **Strict:** Reject all verification failures (default)
- **Warning:** Log failure but execute command
- **Disabled:** Skip verification entirely

---

## Binary Verification

**Method:** Verify checksum and Ed25519 signature before installation

**File:** `agent/internal/orchestrator/update_handler.go`

```go
func (h *UpdateHandler) verifyDownload(binaryData []byte, checksum string) error {
    // 1. Verify checksum
    computedChecksum := sha256.Sum256(binaryData)
    if hex.EncodeToString(computedChecksum[:]) != checksum {
        return errors.New("checksum mismatch")
    }

    // 2. Verify Ed25519 signature
    signature, err := h.downloadBinarySignature()
    if err != nil {
        return err
    }

    publicKey, err := h.LoadCachedPublicKey()
    if err != nil {
        return err
    }

    if !ed25519.Verify(publicKey, binaryData, []byte(signature)) {
        return errors.New("signature verification failed")
    }

    return nil
}

Cross-References


Last reviewed: 2026-06-14