> ## Documentation Index
> Fetch the complete documentation index at: https://docs.phala.com/llms.txt
> Use this file to discover all available pages before exploring further.

# Domain Attestation

> How to verify your data privacy when connecting to TEE applications

This guide shows how to verify that TLS certificates are controlled by a TEE using cryptographic attestation.

For application code verification, see your app's attestation documentation. For security concepts, see [Security Architecture](/phala-cloud/networking/security).

## Which Verification Guide to Follow?

The verification method depends on what the application deployer chose:

| Domain Type                             | When to Use                                       | Operator    |
| --------------------------------------- | ------------------------------------------------- | ----------- |
| **Gateway Domains** (`*.phala.network`) | Your app uses Phala's gateway domain              | Phala Cloud |
| **Custom Domain**                       | Your app uses a custom domain with dstack-ingress | Developer   |

Both provide cryptographic proof of TEE control over TLS certificates. The difference is who operates the certificate infrastructure.

## Gateway Domains

Gateway domains expose attestation endpoints that prove TEE control over TLS certificate private keys.

### What You'll Verify

The gateway TEE publishes cryptographic evidence at `https://GATEWAY-DOMAIN/.dstack/` endpoints that proves:

1. The TLS certificate private keys are generated and controlled by the gateway TEE
2. TEE hardware backs all certificate operations
3. Only the TEE-controlled Let's Encrypt account can issue certificates for gateway domains
4. All historical certificates are accounted for via TEE remote attestation

### 3-Step Verification

**Example**: We'll use `gateway.dstack-pha-prod7.phala.network` - replace with your gateway domain.

#### Step 1: Get Gateway Evidence

The gateway publishes evidence through three endpoints:

```bash theme={"system"}
# Get ACME certificate information
curl -s "https://gateway.dstack-pha-prod7.phala.network/.dstack/acme-info" | jq > acme-info.json

# Get gateway application information
curl -s "https://gateway.dstack-pha-prod7.phala.network/.dstack/app-info" | jq > app-info.json
```

**Expected output from acme-info.json**:

```json theme={"system"}
{
  "account_uri": "https://acme-v02.api.letsencrypt.org/acme/acct/2584877296",
  "account_quote": { tdx-quote-with-eventlogs },
  "hist_keys": ["<base64-pubkey-1>"],
  "quoted_hist_keys": [
    {"public_key": "<base64>", "quote": { tdx-quote-with-eventlogs } },
    {"public_key": "<base64>", "quote": { tdx-quote-with-eventlogs } }
  ],
  "active_cert": "-----BEGIN CERTIFICATE-----\n...",
  "base_domain": "dstack-pha-prod7.phala.network"
}
```

**What this means**: The gateway provides its Let's Encrypt account, all certificate public keys (current and historical), and TDX quotes proving the TEE generated these keys.

#### Step 2: Verify Certificate Matches TDX Quotes

Check that the served certificate matches the TEE-quoted keys:

```bash theme={"system"}
# Get the public key from the served certificate
openssl s_client -connect gateway.dstack-pha-prod7.phala.network:443 </dev/null 2>/dev/null | \
  openssl x509 -pubkey -noout > served-pubkey.pem

# Get the public key from the evidence certificate
cat acme-info.json | jq -r '.active_cert' | \
  openssl x509 -pubkey -noout > evidence-pubkey.pem

# Compare the public keys
diff served-pubkey.pem evidence-pubkey.pem
```

**Expected**: No output (files are identical).

Now verify the TEE hardware signed the certificate public key:

```bash theme={"system"}
# Step 1: Prepare the public key for hashing
cat acme-info.json | jq -r '.quoted_hist_keys[0].public_key' | xxd -r -p > pubkey.bin
(echo -n "zt-cert:" && cat pubkey.bin) | sha512sum
# Output: 68f04e2b77f9ca8324d49ce916a5a7ebc6a715027d68fba4e7d3fb60f0f841a8  -

# Step 2: Search for this hash in the TDX quote's report_data
jq -r '.quoted_hist_keys[0].quote | fromjson | .report_data' acme-info.json | \
  grep -o "68f04e2b77f9ca8324d49ce916a5a7ebc6a715027d68fba4e7d3fb60f0f841a8"
# Output: 68f04e2b77f9ca8324d49ce916a5a7ebc6a715027d68fba4e7d3fb60f0f841a8
```

**What this means**: If you see the same hash in both outputs, Intel TDX hardware has cryptographically signed this public key. Copy the hash from step 1 and search for it in step 2 - they must match exactly.

Please follow the [Attestation Verification tutorial](/phala-cloud/attestation/verifying-attestation) to further verify the remote attestation of the gateway. It ensures the implementation and the execution environment of the gateway is secure.

#### Step 3: Check Domain Protection and Certificate History

Verify only this TEE can issue certificates:

```bash theme={"system"}
# Check ALL certificates ever issued for the gateway domain
curl -s "https://crt.sh/?q=%.dstack-pha-prod7.phala.network&output=json" | \
  jq -r '.[] | "\(.not_before) to \(.not_after): \(.issuer_name)"' | head -10

# Get the TEE's ACME account
cat acme-info.json | jq -r '.account_uri'
# Output: https://acme-v02.api.letsencrypt.org/acme/acct/2584877296

# Check DNS CAA records for the base domain
dig +short CAA dstack-pha-prod7.phala.network
```

**Example output**:

```
# Certificate history
2025-01-15T08:23:45 to 2025-04-15T08:23:44: C=US, O=Let's Encrypt, CN=E5
2024-12-01T10:15:22 to 2025-03-01T10:15:21: C=US, O=Let's Encrypt, CN=R3

# ACME account
https://acme-v02.api.letsencrypt.org/acme/acct/2584877296

# CAA record
0 issue "letsencrypt.org;validationmethods=dns-01;accounturi=https://acme-v02.api.letsencrypt.org/acme/acct/2584877296"
```

Verify the following:

* All certificates are from Let's Encrypt (no other CAs)
* All the CAA record matches the account\_uri from the TEE
* Historical keys in `hist_keys` correspond to certificates in CT logs

### Gateway Evidence Endpoints Reference

| Endpoint             | Contains                                   | Proves                          |
| -------------------- | ------------------------------------------ | ------------------------------- |
| `/.dstack/index`     | List of available endpoints                | Gateway discovery               |
| `/.dstack/app-info`  | App ID, instance ID, device ID, TCB info   | TEE application identity        |
| `/.dstack/acme-info` | ACME account, certificate keys, TDX quotes | Certificate control and history |

The `acme-info` response structure:

| Field              | Type   | Purpose                                                        |
| ------------------ | ------ | -------------------------------------------------------------- |
| `account_uri`      | String | Let's Encrypt account URI                                      |
| `account_quote`    | String | TDX quote proving TEE controls the ACME account                |
| `hist_keys`        | Array  | All certificate public keys (current + historical)             |
| `quoted_hist_keys` | Array  | Public keys with TDX quotes proving TEE generated them         |
| `active_cert`      | String | Currently active certificate (PEM format)                      |
| `base_domain`      | String | Base domain for gateway (e.g., dstack-pha-prod7.phala.network) |

### Troubleshooting

**"Connection refused to /.dstack/ endpoints"**: These endpoints are only accessible via the gateway subdomain: `gateway.dstack-pha-prod7.phala.network`

**"Certificate doesn't match quoted keys"**: The gateway may have recently renewed certificates. Re-fetch the evidence with a fresh `acme-info` request.

**"Multiple ACME accounts in history"**: Gateway upgrades or migrations may result in new ACME accounts. Check that the CAA record matches the current account\_uri, and verify old certificates have expired.

### What You've Verified

When all checks pass, you've cryptographically proven:

* **Zero-trust TLS**: The gateway TEE controls certificate private keys, verifiable via TDX attestation
* **Phala-operated infrastructure**: Phala Network operates the gateway TEE and maintains CAA records
* **Certificate transparency**: All certificates are publicly auditable via CT logs

**Key difference from custom domains**: With gateway domains, Phala operates the certificate infrastructure. With custom domains, the application deployer operates it. Both provide cryptographic proof of TEE control.

## Custom Domains

Custom domains use dstack-ingress running in your application's TEE to manage certificates. The application deployer operates the certificate infrastructure.

### What You'll Verify

Your TEE publishes cryptographic evidence at `https://your-domain.com/evidences/` that proves:

1. The TLS certificate is controlled exclusively by this TEE
2. Intel TDX hardware backs the attestation
3. No one else can issue certificates for this domain

Live example: [custom-domain-demo.phala.systems/evidences/](https://custom-domain-demo.phala.systems/evidences/)

### Prerequisites

Before starting, you'll need:

* Your domain name (e.g., `your-domain.com`)
* `curl`, `jq`, `openssl`, and `dig` commands installed
* 3 minutes to complete all verifications

### Simple 3-Step Verification

**Example**: We'll use `custom-domain-demo.phala.systems` - just replace with your domain.

#### Step 1: Get the Evidence Files

Your TEE publishes 4 files that prove it controls the certificate:

```bash theme={"system"}
# Download the evidence files (4 files total)
curl -sO https://your-domain.com/evidences/quote.json
curl -sO https://your-domain.com/evidences/sha256sum.txt
curl -sO https://your-domain.com/evidences/cert.pem
curl -sO https://your-domain.com/evidences/acme-account.json

# Verify the files haven't been tampered with
sha256sum -c sha256sum.txt
```

**Expected output**:

```
acme-account.json: OK
cert.pem: OK
```

This means the files are authentic.

#### Step 2: Verify the Certificate Matches

Check that the evidence matches what's actually being served:

```bash theme={"system"}
# Compare the served certificate with the evidence certificate
echo | openssl s_client -connect your-domain.com:443 2>/dev/null | \
  openssl x509 -fingerprint -sha256 -noout
openssl x509 -in cert.pem -fingerprint -sha256 -noout
```

**What to look for**: Both fingerprints should be identical. For example:

```
SHA256 Fingerprint=62:89:C4:19:E6:F6:B6:50:11:F9:7D:E1:CF:FD:EE:5A:CE:2C:A3:38:24:F0:DE:5F:9E:2C:01:A3:72:D3:8B:DE
SHA256 Fingerprint=62:89:C4:19:E6:F6:B6:50:11:F9:7D:E1:CF:FD:EE:5A:CE:2C:A3:38:24:F0:DE:5F:9E:2C:01:A3:72:D3:8B:DE
```

Now verify the TEE hardware signed these files:

```bash theme={"system"}
# Step 1: Get the hash of sha256sum.txt
sha256sum sha256sum.txt
# Output: 7cd338a801531e88a5af8478aa185cfc51baf7501319446ce2f94dade56a0988  sha256sum.txt

# Step 2: Search for this complete hash in the TDX quote
cat quote.json | jq -r '.quote' | grep -o "7cd338a801531e88a5af8478aa185cfc51baf7501319446ce2f94dade56a0988"
# Output: 7cd338a801531e88a5af8478aa185cfc51baf7501319446ce2f94dade56a0988
```

**What this means**: If you see the same 64-character hash in both outputs, Intel TDX hardware has cryptographically signed your evidence files. Copy the hash from step 1 and search for it in step 2 - they must match exactly.

#### Step 3: Check Domain Protection and Timeline

Make sure only this TEE can get certificates for your domain:

```bash theme={"system"}
# Check ALL certificates ever issued for your domain
curl -s "https://crt.sh/?q=your-domain.com&output=json" | \
  jq -r '.[] | "\(.not_before) to \(.not_after): \(.issuer_name)"' | head -5

# Get the TEE's ACME account number
cat acme-account.json | jq -r '.uri'

# Check if your domain is locked to this account
dig +short CAA your-domain.com
```

**Example output**:

```
# Certificate history (note the dates!)
2025-08-04T06:10:56 to 2025-11-02T06:10:55: C=US, O=Let's Encrypt, CN=E5  ← Current
2025-08-04T06:00:18 to 2025-11-02T06:00:17: C=US, O=Let's Encrypt, CN=E5  ← TEE deployment

# ACME account
https://acme-v02.api.letsencrypt.org/acme/acct/2572685661

# CAA record (contains the same account number)
0 issue "letsencrypt.org;validationmethods=dns-01;accounturi=https://acme-v02.api.letsencrypt.org/acme/acct/2572685661"
```

**Critical timeline check**: If you see certificates issued BEFORE your TEE was deployed (before CAA was set), verify they're either:

* Already expired (check the "to" date)
* Issued by the same ACME account (meaning they were from a previous TEE deployment)

If unexpired certificates exist from before CAA setup, they could potentially intercept traffic!

### Understanding the Results

When all verifications pass, you've proven:

✅ **Exclusive TEE Control**: Only this specific TEE instance has the private key for your TLS certificate

✅ **Hardware-Backed Security**: Intel TDX hardware cryptographically signed the evidence, proving it's a genuine TEE

✅ **Domain Protection**: CAA DNS records prevent anyone else (even with domain access) from issuing certificates

✅ **Complete Chain of Trust**: Every link from TDX hardware → evidence files → certificate → your connection is verified

### Evidence Files Reference

<Frame>
  <img src="https://mintcdn.com/phalanetwork-1606097b/HhZAgNWhhdRirRzb/images/evidence-files-directory.png?fit=max&auto=format&n=HhZAgNWhhdRirRzb&q=85&s=b0bcf11bc4281a8c0f61b4b883bede34" alt="Browser showing /evidences/ directory listing with four files: acme-account.json, cert.pem, quote.json, and sha256sum.txt with timestamps and file sizes" width="3680" height="2382" data-path="images/evidence-files-directory.png" />
</Frame>

The four evidence files at `/evidences/` work together:

| File                | Contains                               | Proves                              |
| ------------------- | -------------------------------------- | ----------------------------------- |
| `quote.json`        | TDX attestation with embedded hash     | Hardware generated the evidence     |
| `sha256sum.txt`     | SHA256 of cert.pem + acme-account.json | Links certificate to ACME account   |
| `cert.pem`          | Current TLS certificate                | What's being served to clients      |
| `acme-account.json` | ACME account URI                       | Which account controls certificates |

### Troubleshooting

**"Files not found at /evidences/"**: Ensure your domain uses custom domain setup with `SET_CAA=true`

**"Certificate doesn't match"**: The TEE may have renewed the certificate. Re-download evidence files.

**"Hash not in quote"**: Verify you're checking a production TEE deployment, not a test instance.

**"CAA record missing"**: The domain owner needs to set CAA records pointing to the TEE's ACME account.

### Going Deeper: Application Trust

While you've verified the network connection is secure, the TLS private key is only as trustworthy as the code handling it. The key management software (dstack-ingress) runs inside the TEE and is open-source auditable code. To verify the exact code handling your keys matches what's deployed, check the compose-hash in the TEE's event log against the published source code. This ensures no malicious code can access or leak your private keys.

Learn more: [Application Attestation Documentation](/phala-cloud/attestation)

### Complete Security Checklist

<Note>
  **Network Security** (covered above):

  * ✅ Evidence files verify TEE control
  * ✅ TDX attestation proves hardware backing
  * ✅ CAA records prevent unauthorized certificates
  * ✅ Certificate timeline shows no pre-deployment threats

  **Advanced Verification** (for maximum security):

  * ⚠️ Application code trust - Verify compose-hash matches source code
  * ⚠️ Certificate timeline - Ensure no valid pre-CAA certificates exist
  * ⚠️ Continuous monitoring - Watch CT logs for unexpected certificates

  For detailed application verification: [Attestation Guide](/phala-cloud/attestation)
</Note>

## Next Steps

### Monitoring

Set up alerts on [crt.sh](https://crt.sh) to detect unexpected certificate issuance:

* Gateway domains: `%.dstack-pha-prod7.phala.network`
* Custom domains: `your-domain.com`

### Development

* **Gateway verification**: Integrate attestation checks into your security monitoring workflow
* **Custom domains**: Enable CAA records with `SET_CAA=true` in your deployment configuration

### Security Auditing

Review the source code to understand certificate management:

* [Gateway implementation](https://github.com/Dstack-TEE/dstack/tree/master/gateway)
* [Custom domain ingress](https://github.com/Dstack-TEE/dstack-examples/tree/main/custom-domain/dstack-ingress)
