This page shows the full end-to-end flow that a wafpass-server performs
when it submits a validation run to the WAF++ validation gateway.
The gateway is the central trust anchor: it issues sub-CA certificates to trusted servers, receives signed validation runs, verifies them, and returns an official validation envelope that any third party can verify against the gateway root CA.
1. Server certificate (issued earlier)
Before a server can submit anything, an administrator registers it in the gateway admin UI and issues a sub-CA certificate. The server stores the private key securely and sends only the certificate with each submission.
curl -X POST https://validate.waf2p.dev/api/admin/server-certs \
-H "Authorization: Bearer <admin-token>" \
-H "Content-Type: application/json" \
-d '{
"server_id": "acme-prod-1",
"server_public_key_pem": "-----BEGIN PUBLIC KEY-----\n...\n-----END PUBLIC KEY-----",
"validity_days": 365
}'
The returned certificate is stored on the server as server.crt.
2. Build a local attestation
The server runs the WAF++ checks locally and signs the canonical run hash with its own Ed25519 attestation key (the private counterpart of the public key that was registered with the gateway).
wafpass check ./infra --output json --project acme-platform/prod --branch main
This produces a run JSON. The server then computes:
canonical_hash = sha256(canonicalize(run_json)).hexdigest()
signature = ed25519_sign(canonical_hash, server_attestation_private_key)
3. Submit to the gateway
The server POSTs the full payload to the gateway. You can download the exact example body used below:
Request
curl -X POST https://validate.waf2p.dev/api/v1/validations \
-H "Content-Type: application/json" \
-H "X-Api-Key: wafpass_..." \
--data-binary @wafpp-submit-payload.json
Request body
{
"server_certificate": "-----BEGIN CERTIFICATE-----\nMIIBkTCB+wIJAKHBfpEaq3YDMA0GCSqGSIb3DQEBCwUAMBExDzANBgNVBAMMBndh\nZnBhc3MwHhcNMjYwODE2MDYwMDAwWhcNMjcwODE2MDYwMDAwWjARMQ8wDQYDVQQD\nDAZ3YWZwYXNzMFwwDQYJKoZIhvcNAQEBBQADSwAwSAJBAKHBfpEaq3YDMqWh7pEy\n8xQH1vLWNV8j7Y7BgQKpkCM+wPFuqeM8J8bAqWh7pE3y8xQH1vLWNV8j7Y7BgQKp\nkCMDH1sCAwEAATANBgkqhkiG9w0BAQsFAANBAF8Q1vLWNV8j7Y7BgQKpkCM+wPFu\nqeM8J8bAqWh7pE3y8xQH1vLWNV8j7Y7BgQKpkCM+wPFuqeM8J8bAqWh7pE3y8xQ=\n-----END CERTIFICATE-----",
"local_attestation": {
"canonical_hash": "7184231525be8173ccb7eb0b5fc804630e37c49c2ec3c511b3c47b8d875a54a6",
"public_key": "-----BEGIN PUBLIC KEY-----\nMCowBQYDK2VwAyEAwPFuqeM8J8bAqWh7pE3y8xQH1vLWNV8j7Y7BgQKpkCM=\n-----END PUBLIC KEY-----",
"signature": "f8c3b2a1d4e5f6a7b8c9d0e1f2a3b4c5d6e7f8a9b0c1d2e3f4a5b6c7d8e9f0a1b2c3d4e5f6a7b8c9d0e1f2a3b4c5d6e7f8a9b0c1d2e3f4a5b6c7d8e9f0a1b2",
"algorithm": "Ed25519"
},
"run": {
"project": "acme-platform/prod",
"target_url": "https://api.acme.example.com",
"started_at": "2026-08-16T11:42:00Z",
"finished_at": "2026-08-16T11:43:12Z",
"checks": [
{
"id": "waf-ctl-001",
"control": "Encrypt data at rest",
"status": "pass",
"severity": "critical",
"resource": "aws_rds_cluster.primary",
"message": "Storage encryption is enabled with AWS managed KMS key."
},
{
"id": "waf-ctl-042",
"control": "Restrict inbound network access",
"status": "pass",
"severity": "critical",
"resource": "aws_security_group.app",
"message": "Only ports 443 and 80 are open to the load balancer security group."
},
{
"id": "waf-ctl-017",
"control": "Enable audit logging",
"status": "fail",
"severity": "high",
"resource": "aws_s3_bucket.logs",
"message": "Object-level logging is not configured for this bucket."
}
]
}
}
4. Gateway response
If the server certificate is valid and registered, and the local attestation verifies, the gateway signs the canonical run hash with its intermediate CA and returns the official validation envelope.
Download example response JSON
{
"id": "waf-ex-12345678-1234-1234-1234-123456789abc",
"validation_id": "waf-ex-12345678-1234-1234-1234-123456789abc",
"status": "valid",
"server_id": "acme-prod-1",
"canonical_hash": "7184231525be8173ccb7eb0b5fc804630e37c49c2ec3c511b3c47b8d875a54a6",
"signed_at": "2026-08-16T11:43:15.000000Z",
"server_public_key": "-----BEGIN PUBLIC KEY-----\nMCowBQYDK2VwAyEAwPFuqeM8J8bAqWh7pE3y8xQH1vLWNV8j7Y7BgQKpkCM=\n-----END PUBLIC KEY-----",
"server_signature": "f8c3b2a1d4e5f6a7b8c9d0e1f2a3b4c5d6e7f8a9b0c1d2e3f4a5b6c7d8e9f0a1b2c3d4e5f6a7b8c9d0e1f2a3b4c5d6e7f8a9b0c1d2e3f4a5b6c7d8e9f0a1b2",
"certificate_chain": [
"-----BEGIN CERTIFICATE-----\n...\n-----END CERTIFICATE-----",
"-----BEGIN CERTIFICATE-----\n...\n-----END CERTIFICATE-----"
],
"verify_url": "https://validate.waf2p.dev/api/v1/validations/waf-ex-12345678-1234-1234-1234-123456789abc/verify",
"badge_url": "https://validate.waf2p.dev/api/v1/validations/waf-ex-12345678-1234-1234-1234-123456789abc/badge.svg"
}
5. Verify the validation
Anyone can verify the result without trusting the submitting server:
curl https://validate.waf2p.dev/api/v1/validations/waf-ex-12345678-1234-1234-1234-123456789abc/verify
The gateway checks the certificate chain against its root CA, verifies the
canonical hash, and returns the current status (valid or revoked).
6. Live local example
This flow was executed against the development gateway running at
http://localhost:8001:
# 1. Run the WAF++ checks
wafpass check \
--controls-dir ./controls \
--project wafpass-live-example \
--output json \
--no-state \
main.tf
# 2. Request official validation
wafpass validate official \
--validation-url http://localhost:8001/api/v1/validations \
--api-key wafpass_9TYsIJ9gPKzAE152DxYgaBYmxK-7w5OrG_ekaVMAaUk \
--server-certificate /tmp/live-server.crt \
/tmp/wafpass-result.json
Resulting validation:
| Field | Value |
|---|---|
| Validation ID | e59c8ab3-f969-44be-867d-8c9e88bd7317 |
| Canonical hash | 98fa6a9776401d839cbd136d82d4edbda97e31e4757a04d8cc688e47659d6521 |
| Status | valid |
| Verification URL | http://localhost:8001/api/v1/validations/e59c8ab3-f969-44be-867d-8c9e88bd7317/verify |
| Badge URL | http://localhost:8001/api/v1/validations/e59c8ab3-f969-44be-867d-8c9e88bd7317/badge.svg |
# Local offline verification
wafpass verify /private/tmp/wafpass-validation-98fa6a9776401d83.json
# → ✓ Local verification passed envelope verified
# Public gateway verification
curl http://localhost:8001/api/v1/validations/e59c8ab3-f969-44be-867d-8c9e88bd7317/verify