- Load WELIST_PING_DELEGATION_FILE into a typed OnionDelegation
- Send the certificate only with v2 pings for onion hosts
- Validate the onion host, expiry and delegated key against
BAL_SERVER_URL and SSL_KEY_PATH at startup; disable delegation
with a warning on any mismatch
- Stop sending unsigned info/base_fee/version with v1 pings so
v1 remains liveness-only
- Document v1/v2 metadata handling and onion delegation implications
- Add contrib/make_onion_delegation.py to issue certificates offline,
with Ed25519 key validation and clean CLI error handling
openssl pkey -in private_key.pem -pubout -outform DER | base64 -w0
```
The two commands must print the same base64 string.
Optionally check that the legacy `/.pub_key.pem` endpoint serves the same key:
```bash
curl -s https://we.example.com/.pub_key.pem \
| openssl pkey -pubin -outform DER \
| base64 -w0
```
This third check is only meaningful when `BAL_SERVER_PUB_KEY_PATH` and
`SSL_KEY_PATH` reference the same key pair, which is the recommended setup. The
endpoint serves whatever `BAL_SERVER_PUB_KEY_PATH` points at; if the two
settings use different pairs, compare the TXT record with `SSL_KEY_PATH` only.
---
## 8. Test a v2 ping
Wait for the next block, or restart the pusher. With trace logging enabled you
should see:
```text
canonical message to be sent: WELIST-PING-V2\n{"base_fee":...
Report to welist(...) status=200 body="ok"
```
The WeTime service should log `PING ADDED` and refresh the executor's
`last_update`. After a valid v2 ping, signed `info`, `base_fee`, and `version`
values are persisted.
A response of `"ko"` means the signature was rejected. Check the service logs
for the specific `PING REJECTED` reason.
---
## 9. Key rotation
Multiple TXT records are supported and any one of them can verify a signature.
To rotate without downtime:
1. Publish the new public key as an additional TXT record.
2. Switch `SSL_KEY_PATH` to the new private key and restart the pusher.
3. Wait at least the old TXT TTL, and no more than the 86400-second cache cap.
4. Remove the old TXT record.
The service stores a key only after it verifies a signature, so an invalid DNS
answer cannot poison the cache. A refreshed TXT answer replaces the cached v2
keys for that host.
---
## 10. Troubleshooting
| Service log | Cause | Fix |
|-------------|-------|-----|
| `no TXT records` | Wrong record name or not propagated | Query `_welist-key.<host>` exactly |
| `zone is not DNSSEC-signed` | DNSSEC not enabled or DS missing | Enable DNSSEC and publish the DS record |
| `DNSSEC validation failed` | Expired/bogus signatures, clock skew, broken chain | Check with `delv` or a DNSSEC debugger |
| `DNSSEC status is indeterminate` | Upstream resolver strips DNSSEC data | Set `WELIST_DNS_NAMESERVERS` to a capable resolver |
| `dns unavailable` | Resolver unreachable or invalid configuration | Check `WELIST_DNS_NAMESERVERS` and `WELIST_DNSSEC_TRUST_ANCHOR` |
| `CNAME answers are not accepted` | `_welist-key` is an alias | Publish a real TXT record |
| `malformed record` | Wrong version, algorithm, or syntax | Use `v=we1; alg=ed25519; key=...` |
| `invalid key` | Not a base64 Ed25519 SPKI DER | Regenerate with the `openssl` command above |
| `v2 DNS lookup requires a hostname` | `BAL_SERVER_URL` uses an IP address | Use a DNS hostname |
| `invalid v2 signature` | Key mismatch or non-canonical URL | Ensure the TXT key matches `SSL_KEY_PATH` and the URL has no trailing slash |
| `invalid onion delegation` | Certificate signature does not verify against the onion identity key | Re-issue the certificate with the correct onion key; do not edit `key`/`valid_until` after signing |
| `delegation does not match the ping onion host` | `onion` field differs from `BAL_SERVER_URL` | Re-issue the certificate for the exact host |
| `delegation expired` | `valid_until` is in the past | Re-issue the certificate and restart the pusher |
| `delegation is only supported for onion hosts` | `delegation` sent with a DNS URL | Unset `WELIST_PING_DELEGATION_FILE` for DNS hosts |
| `legacy ping disabled` | v1 ping sent while the service requires v2 | Set `WELIST_PING_SIG_VERSION=2` (or enable legacy on the service) |
Useful diagnostics:
```bash
dig +dnssec TXT _welist-key.we.example.com
delv TXT _welist-key.we.example.com
dig +trace +dnssec TXT _welist-key.we.example.com
```
---
## Onion URLs
A v3 `.onion` address embeds the service's Ed25519 identity key, so no TXT
record is needed. The recommended design keeps that identity key **offline** and
delegates ping signing to a dedicated, rotatable key:
-`ping_private_key.pem` (`SSL_KEY_PATH`) signs every v2 ping.
- The onion identity key signs a delegation certificate once.
- Each onion ping carries the certificate in a `delegation` object.
- The WeTime service verifies the certificate against the onion address, then
verifies the ping signature with the delegated key.
Without a `delegation` object the service still accepts pings signed directly by
the onion identity key. That fallback exists for compatibility; it requires the
identity key to be online and should not be used for new deployments.
The ping `url` must itself use the `.onion` host. The `onion_url` database field
is display-only and does not affect authentication.
### Certificate format
The request carries:
```json
{
"onion":"<address>.onion",
"key":"<base64 SPKI DER of the delegated Ed25519 key>",
"valid_until":1767225600,
"signature":"<base64 Ed25519 signature by the onion identity key>"
| 10 | [`10_dnssec_key_publishing.md`](10_dnssec_key_publishing.md) | Publishing the v2 WeTime key via DNSSEC TXT, v3 onion identity, or delegated onion ping key |
---
Reference in New Issue
Block a user
Blocking a user prevents them from interacting with repositories, such as opening or commenting on pull requests or issues. Learn more about blocking a user.