A container registry that uses the AT Protocol for manifest storage and S3 for blob storage.
atcr.io
docker
container
atproto
go
1# Hold-as-Certificate-Authority Architecture
2
3## ⚠️ Important Notice
4
5This document describes an **optional enterprise feature** for X.509 PKI compliance. The hold-as-CA approach introduces **centralization trade-offs** that contradict ATProto's decentralized philosophy.
6
7**Default Recommendation:** Use [plugin-based integration](./INTEGRATION_STRATEGY.md) instead. Only implement hold-as-CA if your organization has specific X.509 PKI compliance requirements.
8
9## Overview
10
11The hold-as-CA architecture allows ATCR to generate Notation/Notary v2-compatible signatures by having hold services act as Certificate Authorities that issue X.509 certificates for users.
12
13### The Problem
14
15- **ATProto signatures** use K-256 (secp256k1) elliptic curve
16- **Notation** only supports P-256, P-384, P-521 elliptic curves
17- **Cannot convert** K-256 signatures to P-256 (different cryptographic curves)
18- **Must re-sign** with P-256 keys for Notation compatibility
19
20### The Solution
21
22Hold services act as trusted Certificate Authorities (CAs):
23
241. User pushes image → Manifest signed by PDS with K-256 (ATProto)
252. Hold verifies ATProto signature is valid
263. Hold generates ephemeral P-256 key pair for user
274. Hold issues X.509 certificate to user's DID
285. Hold signs manifest with P-256 key
296. Hold creates Notation signature envelope (JWS format)
307. Stores both ATProto and Notation signatures
31
32**Result:** Images have two signatures:
33- **ATProto signature** (K-256) - Decentralized, DID-based
34- **Notation signature** (P-256) - Centralized, X.509 PKI
35
36## Architecture
37
38### Certificate Chain
39
40```
41Hold Root CA Certificate (self-signed, P-256)
42 └── User Certificate (issued to DID, P-256)
43 └── Image Manifest Signature
44```
45
46**Hold Root CA:**
47```
48Subject: CN=ATCR Hold CA - did:web:hold01.atcr.io
49Issuer: Self (self-signed)
50Key Usage: Digital Signature, Certificate Sign
51Basic Constraints: CA=true, pathLen=1
52Algorithm: ECDSA P-256
53Validity: 10 years
54```
55
56**User Certificate:**
57```
58Subject: CN=did:plc:alice123
59SAN: URI:did:plc:alice123
60Issuer: Hold Root CA
61Key Usage: Digital Signature
62Extended Key Usage: Code Signing
63Algorithm: ECDSA P-256
64Validity: 24 hours (short-lived)
65```
66
67### Push Flow
68
69```
70┌──────────────────────────────────────────────────────┐
71│ 1. User: docker push atcr.io/alice/myapp:latest │
72└────────────────────┬─────────────────────────────────┘
73 ↓
74┌──────────────────────────────────────────────────────┐
75│ 2. AppView stores manifest in alice's PDS │
76│ - PDS signs with K-256 (ATProto standard) │
77│ - Signature stored in repository commit │
78└────────────────────┬─────────────────────────────────┘
79 ↓
80┌──────────────────────────────────────────────────────┐
81│ 3. AppView requests hold to co-sign │
82│ POST /xrpc/io.atcr.hold.coSignManifest │
83│ { │
84│ "userDid": "did:plc:alice123", │
85│ "manifestDigest": "sha256:abc123...", │
86│ "atprotoSignature": {...} │
87│ } │
88└────────────────────┬─────────────────────────────────┘
89 ↓
90┌──────────────────────────────────────────────────────┐
91│ 4. Hold verifies ATProto signature │
92│ a. Resolve alice's DID → public key │
93│ b. Fetch commit from alice's PDS │
94│ c. Verify K-256 signature │
95│ d. Ensure signature is valid │
96│ │
97│ If verification fails → REJECT │
98└────────────────────┬─────────────────────────────────┘
99 ↓
100┌──────────────────────────────────────────────────────┐
101│ 5. Hold generates ephemeral P-256 key pair │
102│ privateKey := ecdsa.GenerateKey(elliptic.P256()) │
103└────────────────────┬─────────────────────────────────┘
104 ↓
105┌──────────────────────────────────────────────────────┐
106│ 6. Hold issues X.509 certificate │
107│ Subject: CN=did:plc:alice123 │
108│ SAN: URI:did:plc:alice123 │
109│ Issuer: Hold CA │
110│ NotBefore: now │
111│ NotAfter: now + 24 hours │
112│ KeyUsage: Digital Signature │
113│ ExtKeyUsage: Code Signing │
114│ │
115│ Sign certificate with hold's CA private key │
116└────────────────────┬─────────────────────────────────┘
117 ↓
118┌──────────────────────────────────────────────────────┐
119│ 7. Hold signs manifest digest │
120│ hash := SHA256(manifestBytes) │
121│ signature := ECDSA_P256(hash, privateKey) │
122└────────────────────┬─────────────────────────────────┘
123 ↓
124┌──────────────────────────────────────────────────────┐
125│ 8. Hold creates Notation JWS envelope │
126│ { │
127│ "protected": {...}, │
128│ "payload": "base64(manifestDigest)", │
129│ "signature": "base64(p256Signature)", │
130│ "header": { │
131│ "x5c": [ │
132│ "base64(userCert)", │
133│ "base64(holdCACert)" │
134│ ] │
135│ } │
136│ } │
137└────────────────────┬─────────────────────────────────┘
138 ↓
139┌──────────────────────────────────────────────────────┐
140│ 9. Hold returns signature to AppView │
141└────────────────────┬─────────────────────────────────┘
142 ↓
143┌──────────────────────────────────────────────────────┐
144│ 10. AppView stores Notation signature │
145│ - Create ORAS artifact manifest │
146│ - Upload JWS envelope as layer blob │
147│ - Link to image via subject field │
148│ - artifactType: application/vnd.cncf.notary... │
149└──────────────────────────────────────────────────────┘
150```
151
152### Verification Flow
153
154```
155┌──────────────────────────────────────────────────────┐
156│ User: notation verify atcr.io/alice/myapp:latest │
157└────────────────────┬─────────────────────────────────┘
158 ↓
159┌──────────────────────────────────────────────────────┐
160│ 1. Notation queries Referrers API │
161│ GET /v2/alice/myapp/referrers/sha256:abc123 │
162│ → Discovers Notation signature artifact │
163└────────────────────┬─────────────────────────────────┘
164 ↓
165┌──────────────────────────────────────────────────────┐
166│ 2. Notation downloads JWS envelope │
167│ - Parses JSON Web Signature │
168│ - Extracts certificate chain from x5c header │
169└────────────────────┬─────────────────────────────────┘
170 ↓
171┌──────────────────────────────────────────────────────┐
172│ 3. Notation validates certificate chain │
173│ a. User cert issued by Hold CA? ✓ │
174│ b. Hold CA cert in trust store? ✓ │
175│ c. Certificate not expired? ✓ │
176│ d. Key usage correct? ✓ │
177│ e. Subject matches policy? ✓ │
178└────────────────────┬─────────────────────────────────┘
179 ↓
180┌──────────────────────────────────────────────────────┐
181│ 4. Notation verifies signature │
182│ a. Extract public key from user certificate │
183│ b. Compute manifest hash: SHA256(manifest) │
184│ c. Verify: ECDSA_P256(hash, sig, pubKey) ✓ │
185└────────────────────┬─────────────────────────────────┘
186 ↓
187┌──────────────────────────────────────────────────────┐
188│ 5. Success: Image verified ✓ │
189│ Signed by: did:plc:alice123 (via Hold CA) │
190└──────────────────────────────────────────────────────┘
191```
192
193## Implementation
194
195### Hold CA Certificate Generation
196
197```go
198// cmd/hold/main.go - CA initialization
199func (h *Hold) initializeCA(ctx context.Context) error {
200 caKeyPath := filepath.Join(h.config.DataDir, "ca-private-key.pem")
201 caCertPath := filepath.Join(h.config.DataDir, "ca-certificate.pem")
202
203 // Load existing CA or generate new one
204 if exists(caKeyPath) && exists(caCertPath) {
205 h.caKey = loadPrivateKey(caKeyPath)
206 h.caCert = loadCertificate(caCertPath)
207 return nil
208 }
209
210 // Generate P-256 key pair for CA
211 caKey, err := ecdsa.GenerateKey(elliptic.P256(), rand.Reader)
212 if err != nil {
213 return fmt.Errorf("failed to generate CA key: %w", err)
214 }
215
216 // Create CA certificate template
217 serialNumber, _ := rand.Int(rand.Reader, new(big.Int).Lsh(big.NewInt(1), 128))
218
219 template := &x509.Certificate{
220 SerialNumber: serialNumber,
221 Subject: pkix.Name{
222 CommonName: fmt.Sprintf("ATCR Hold CA - %s", h.DID),
223 },
224 NotBefore: time.Now(),
225 NotAfter: time.Now().AddDate(10, 0, 0), // 10 years
226
227 KeyUsage: x509.KeyUsageDigitalSignature | x509.KeyUsageCertSign,
228 BasicConstraintsValid: true,
229 IsCA: true,
230 MaxPathLen: 1, // Can only issue end-entity certificates
231 }
232
233 // Self-sign
234 certDER, err := x509.CreateCertificate(
235 rand.Reader,
236 template,
237 template, // Self-signed: issuer = subject
238 &caKey.PublicKey,
239 caKey,
240 )
241 if err != nil {
242 return fmt.Errorf("failed to create CA certificate: %w", err)
243 }
244
245 caCert, _ := x509.ParseCertificate(certDER)
246
247 // Save to disk (0600 permissions)
248 savePrivateKey(caKeyPath, caKey)
249 saveCertificate(caCertPath, caCert)
250
251 h.caKey = caKey
252 h.caCert = caCert
253
254 log.Info("Generated new CA certificate", "did", h.DID, "expires", caCert.NotAfter)
255 return nil
256}
257```
258
259### User Certificate Issuance
260
261```go
262// pkg/hold/cosign.go
263func (h *Hold) issueUserCertificate(userDID string) (*x509.Certificate, *ecdsa.PrivateKey, error) {
264 // Generate ephemeral P-256 key for user
265 userKey, err := ecdsa.GenerateKey(elliptic.P256(), rand.Reader)
266 if err != nil {
267 return nil, nil, fmt.Errorf("failed to generate user key: %w", err)
268 }
269
270 serialNumber, _ := rand.Int(rand.Reader, new(big.Int).Lsh(big.NewInt(1), 128))
271
272 // Parse DID for SAN
273 sanURI, _ := url.Parse(userDID)
274
275 template := &x509.Certificate{
276 SerialNumber: serialNumber,
277 Subject: pkix.Name{
278 CommonName: userDID,
279 },
280 URIs: []*url.URL{sanURI}, // Subject Alternative Name
281
282 NotBefore: time.Now(),
283 NotAfter: time.Now().Add(24 * time.Hour), // Short-lived: 24 hours
284
285 KeyUsage: x509.KeyUsageDigitalSignature,
286 ExtKeyUsage: []x509.ExtKeyUsage{x509.ExtKeyUsageCodeSigning},
287 BasicConstraintsValid: true,
288 IsCA: false,
289 }
290
291 // Sign with hold's CA key
292 certDER, err := x509.CreateCertificate(
293 rand.Reader,
294 template,
295 h.caCert, // Issuer: Hold CA
296 &userKey.PublicKey,
297 h.caKey, // Sign with CA private key
298 )
299 if err != nil {
300 return nil, nil, fmt.Errorf("failed to create user certificate: %w", err)
301 }
302
303 userCert, _ := x509.ParseCertificate(certDER)
304
305 return userCert, userKey, nil
306}
307```
308
309### Co-Signing XRPC Endpoint
310
311```go
312// pkg/hold/oci/xrpc.go
313func (s *Server) handleCoSignManifest(ctx context.Context, req *CoSignRequest) (*CoSignResponse, error) {
314 // 1. Verify caller is authenticated
315 did, err := s.auth.VerifyToken(ctx, req.Token)
316 if err != nil {
317 return nil, fmt.Errorf("authentication failed: %w", err)
318 }
319
320 // 2. Verify ATProto signature
321 valid, err := s.verifyATProtoSignature(ctx, req.UserDID, req.ManifestDigest, req.ATProtoSignature)
322 if err != nil || !valid {
323 return nil, fmt.Errorf("ATProto signature verification failed: %w", err)
324 }
325
326 // 3. Issue certificate for user
327 userCert, userKey, err := s.hold.issueUserCertificate(req.UserDID)
328 if err != nil {
329 return nil, fmt.Errorf("failed to issue certificate: %w", err)
330 }
331
332 // 4. Sign manifest with user's key
333 manifestHash := sha256.Sum256([]byte(req.ManifestDigest))
334 signature, err := ecdsa.SignASN1(rand.Reader, userKey, manifestHash[:])
335 if err != nil {
336 return nil, fmt.Errorf("failed to sign manifest: %w", err)
337 }
338
339 // 5. Create JWS envelope
340 jws, err := s.createJWSEnvelope(signature, userCert, s.hold.caCert, req.ManifestDigest)
341 if err != nil {
342 return nil, fmt.Errorf("failed to create JWS: %w", err)
343 }
344
345 return &CoSignResponse{
346 JWS: jws,
347 Certificate: encodeCertificate(userCert),
348 CACertificate: encodeCertificate(s.hold.caCert),
349 }, nil
350}
351```
352
353## Trust Model
354
355### Centralization Analysis
356
357**ATProto Model (Decentralized):**
358- Each PDS is independent
359- User controls which PDS to use
360- Trust user's DID, not specific infrastructure
361- PDS compromise affects only that PDS's users
362- Multiple PDSs provide redundancy
363
364**Hold-as-CA Model (Centralized):**
365- Hold acts as single Certificate Authority
366- All users must trust hold's CA certificate
367- Hold compromise = attacker can issue certificates for ANY user
368- Hold becomes single point of failure
369- Users depend on hold operator honesty
370
371### What Hold Vouches For
372
373When hold issues a certificate, it attests:
374
375✅ **"I verified that [DID] signed this manifest with ATProto"**
376- Hold validated ATProto signature
377- Hold confirmed signature matches user's DID
378- Hold checked signature at specific time
379
380❌ **"This image is safe"**
381- Hold does NOT audit image contents
382- Certificate ≠ vulnerability scan
383- Signature ≠ security guarantee
384
385❌ **"I control this DID"**
386- Hold does NOT control user's DID
387- DID ownership is independent
388- Hold cannot revoke DIDs
389
390### Threat Model
391
392**Scenario 1: Hold Private Key Compromise**
393
394**Attack:**
395- Attacker steals hold's CA private key
396- Can issue certificates for any DID
397- Can sign malicious images as any user
398
399**Impact:**
400- **CRITICAL** - All users affected
401- Attacker can impersonate any user
402- All signatures become untrustworthy
403
404**Detection:**
405- Certificate Transparency logs (if implemented)
406- Unusual certificate issuance patterns
407- Users report unexpected signatures
408
409**Mitigation:**
410- Store CA key in Hardware Security Module (HSM)
411- Strict access controls
412- Audit logging
413- Regular key rotation
414
415**Recovery:**
416- Revoke compromised CA certificate
417- Generate new CA certificate
418- Re-issue all active certificates
419- Notify all users
420- Update trust stores
421
422---
423
424**Scenario 2: Malicious Hold Operator**
425
426**Attack:**
427- Hold operator issues certificates without verifying ATProto signatures
428- Hold operator signs malicious images
429- Hold operator backdates certificates
430
431**Impact:**
432- **HIGH** - Trust model broken
433- Users receive signed malicious images
434- Difficult to detect without ATProto cross-check
435
436**Detection:**
437- Compare Notation signature timestamp with ATProto commit time
438- Verify ATProto signature exists independently
439- Monitor hold's signing patterns
440
441**Mitigation:**
442- Audit trail linking certificates to ATProto signatures
443- Public transparency logs
444- Multi-signature requirements
445- Periodically verify ATProto signatures
446
447**Recovery:**
448- Identify malicious certificates
449- Revoke hold's CA trust
450- Switch to different hold
451- Re-verify all images
452
453---
454
455**Scenario 3: Certificate Theft**
456
457**Attack:**
458- Attacker steals issued user certificate + private key
459- Uses it to sign malicious images
460
461**Impact:**
462- **LOW-MEDIUM** - Limited scope
463- Affects only specific user/image
464- Short validity period (24 hours)
465
466**Detection:**
467- Unexpected signature timestamps
468- Images signed from unknown locations
469
470**Mitigation:**
471- Short certificate validity (24 hours)
472- Ephemeral keys (not stored long-term)
473- Certificate revocation if detected
474
475**Recovery:**
476- Wait for certificate expiration (24 hours)
477- Revoke specific certificate
478- Investigate compromise source
479
480## Certificate Management
481
482### Expiration Strategy
483
484**Short-Lived Certificates (24 hours):**
485
486**Pros:**
487- ✅ Minimal revocation infrastructure needed
488- ✅ Compromise window is tiny
489- ✅ Automatic cleanup
490- ✅ Lower CRL/OCSP overhead
491
492**Cons:**
493- ❌ Old images become unverifiable quickly
494- ❌ Requires re-signing for historical verification
495- ❌ Storage: multiple signatures for same image
496
497**Solution: On-Demand Re-Signing**
498```
499User pulls old image → Notation verification fails (expired cert)
500→ User requests re-signing: POST /xrpc/io.atcr.hold.reSignManifest
501→ Hold verifies ATProto signature still valid
502→ Hold issues new certificate (24 hours)
503→ Hold creates new Notation signature
504→ User can verify with fresh certificate
505```
506
507### Revocation
508
509**Certificate Revocation List (CRL):**
510```
511Hold publishes CRL at: https://hold01.atcr.io/ca.crl
512
513Notation configured to check CRL:
514{
515 "trustPolicies": [{
516 "name": "atcr-images",
517 "signatureVerification": {
518 "verificationLevel": "strict",
519 "override": {
520 "revocationValidation": "strict"
521 }
522 }
523 }]
524}
525```
526
527**OCSP (Online Certificate Status Protocol):**
528- Hold runs OCSP responder: `https://hold01.atcr.io/ocsp`
529- Real-time certificate status checks
530- Lower overhead than CRL downloads
531
532**Revocation Triggers:**
533- Key compromise detected
534- Malicious signing detected
535- User request
536- DID ownership change
537
538### CA Key Rotation
539
540**Rotation Procedure:**
541
5421. **Generate new CA key pair**
5432. **Create new CA certificate**
5443. **Cross-sign old CA with new CA** (transition period)
5454. **Distribute new CA certificate** to all users
5465. **Begin issuing with new CA** for new signatures
5476. **Grace period** (30 days): Accept both old and new CA
5487. **Retire old CA** after grace period
549
550**Frequency:** Every 2-3 years (longer than short-lived certs)
551
552## Trust Store Distribution
553
554### Problem
555
556Users must add hold's CA certificate to their Notation trust store for verification to work.
557
558### Manual Distribution
559
560```bash
561# 1. Download hold's CA certificate
562curl https://hold01.atcr.io/ca.crt -o hold01-ca.crt
563
564# 2. Verify fingerprint (out-of-band)
565openssl x509 -in hold01-ca.crt -fingerprint -noout
566# Compare with published fingerprint
567
568# 3. Add to Notation trust store
569notation cert add --type ca --store atcr-holds hold01-ca.crt
570```
571
572### Automated Distribution
573
574**ATCR CLI tool:**
575```bash
576atcr trust add hold01.atcr.io
577# → Fetches CA certificate
578# → Verifies via HTTPS + DNSSEC
579# → Adds to Notation trust store
580# → Configures trust policy
581
582atcr trust list
583# → Shows trusted holds with fingerprints
584```
585
586### System-Wide Trust
587
588**For enterprise deployments:**
589
590**Debian/Ubuntu:**
591```bash
592# Install CA certificate system-wide
593cp hold01-ca.crt /usr/local/share/ca-certificates/atcr-hold01.crt
594update-ca-certificates
595```
596
597**RHEL/CentOS:**
598```bash
599cp hold01-ca.crt /etc/pki/ca-trust/source/anchors/
600update-ca-trust
601```
602
603**Container images:**
604```dockerfile
605FROM ubuntu:22.04
606COPY hold01-ca.crt /usr/local/share/ca-certificates/
607RUN update-ca-certificates
608```
609
610## Configuration
611
612### Hold Service
613
614**Environment variables:**
615```bash
616# Enable co-signing feature
617HOLD_COSIGN_ENABLED=true
618
619# CA certificate and key paths
620HOLD_CA_CERT_PATH=/var/lib/atcr/hold/ca-certificate.pem
621HOLD_CA_KEY_PATH=/var/lib/atcr/hold/ca-private-key.pem
622
623# Certificate validity
624HOLD_CERT_VALIDITY_HOURS=24
625
626# OCSP responder
627HOLD_OCSP_ENABLED=true
628HOLD_OCSP_URL=https://hold01.atcr.io/ocsp
629
630# CRL distribution
631HOLD_CRL_ENABLED=true
632HOLD_CRL_URL=https://hold01.atcr.io/ca.crl
633```
634
635### Notation Trust Policy
636
637```json
638{
639 "version": "1.0",
640 "trustPolicies": [{
641 "name": "atcr-images",
642 "registryScopes": ["atcr.io/*/*"],
643 "signatureVerification": {
644 "level": "strict",
645 "override": {
646 "revocationValidation": "strict"
647 }
648 },
649 "trustStores": ["ca:atcr-holds"],
650 "trustedIdentities": [
651 "x509.subject: CN=did:plc:*",
652 "x509.subject: CN=did:web:*"
653 ]
654 }]
655}
656```
657
658## When to Use Hold-as-CA
659
660### ✅ Use When
661
662**Enterprise X.509 PKI Compliance:**
663- Organization requires standard X.509 certificates
664- Existing security policies mandate PKI
665- Audit requirements for certificate chains
666- Integration with existing CA infrastructure
667
668**Tool Compatibility:**
669- Must use standard Notation without plugins
670- Cannot deploy custom verification tools
671- Existing tooling expects X.509 signatures
672
673**Centralized Trust Acceptable:**
674- Organization already uses centralized trust model
675- Hold operator is internal/trusted team
676- Centralization risk is acceptable trade-off
677
678### ❌ Don't Use When
679
680**Default Deployment:**
681- Most users should use [plugin-based approach](./INTEGRATION_STRATEGY.md)
682- Plugins maintain decentralization
683- Plugins reuse existing ATProto signatures
684
685**Small Teams / Startups:**
686- Certificate management overhead too high
687- Don't need X.509 compliance
688- Prefer simpler architecture
689
690**Maximum Decentralization Required:**
691- Cannot accept hold as single trust point
692- Must maintain pure ATProto model
693- Centralization contradicts project goals
694
695## Comparison: Hold-as-CA vs. Plugins
696
697| Aspect | Hold-as-CA | Plugin Approach |
698|--------|------------|----------------|
699| **Standard compliance** | ✅ Full X.509/PKI | ⚠️ Custom verification |
700| **Tool compatibility** | ✅ Notation works unchanged | ❌ Requires plugin install |
701| **Decentralization** | ❌ Centralized (hold CA) | ✅ Decentralized (DIDs) |
702| **ATProto alignment** | ❌ Against philosophy | ✅ ATProto-native |
703| **Signature reuse** | ❌ Must re-sign (P-256) | ✅ Reuses ATProto (K-256) |
704| **Certificate mgmt** | 🔴 High overhead | 🟢 None |
705| **Trust distribution** | 🔴 Must distribute CA cert | 🟢 DID resolution |
706| **Hold compromise** | 🔴 All users affected | 🟢 Metadata only |
707| **Operational cost** | 🔴 High | 🟢 Low |
708| **Use case** | Enterprise PKI | General purpose |
709
710## Recommendations
711
712### Default Approach: Plugins
713
714For most deployments, use plugin-based verification:
715- **Ratify plugin** for Kubernetes
716- **OPA Gatekeeper provider** for policy enforcement
717- **Containerd verifier** for runtime checks
718- **atcr-verify CLI** for general purpose
719
720See [Integration Strategy](./INTEGRATION_STRATEGY.md) for details.
721
722### Optional: Hold-as-CA for Enterprise
723
724Only implement hold-as-CA if you have specific requirements:
725- Enterprise X.509 PKI mandates
726- Cannot use plugins (restricted environments)
727- Accept centralization trade-off
728
729**Implement as opt-in feature:**
730```bash
731# Users explicitly enable co-signing
732docker push atcr.io/alice/myapp:latest --sign=notation
733
734# Or via environment variable
735export ATCR_ENABLE_COSIGN=true
736docker push atcr.io/alice/myapp:latest
737```
738
739### Security Best Practices
740
741**If implementing hold-as-CA:**
742
7431. **Store CA key in HSM** - Never on filesystem
7442. **Audit all certificate issuance** - Log every cert
7453. **Public transparency log** - Publish all certificates
7464. **Short certificate validity** - 24 hours max
7475. **Monitor unusual patterns** - Alert on anomalies
7486. **Regular CA key rotation** - Every 2-3 years
7497. **Cross-check ATProto** - Verify both signatures match
7508. **Incident response plan** - Prepare for compromise
751
752## See Also
753
754- [ATProto Signatures](./ATPROTO_SIGNATURES.md) - How ATProto signing works
755- [Integration Strategy](./INTEGRATION_STRATEGY.md) - Overview of integration approaches
756- [Signature Integration](./SIGNATURE_INTEGRATION.md) - Tool-specific integration guides