Files
metacrypt/clients/go/challenge.go
Kyle Isom 167db48eb4 Add ACME (RFC 8555) server and Go client library
Implements full ACME protocol support in Metacrypt:

- internal/acme: core types, JWS verification (ES256/384/512 + RS256),
  nonce store, per-mount handler, all RFC 8555 protocol endpoints,
  HTTP-01 and DNS-01 challenge validation, EAB management
- internal/server/acme.go: management REST routes (EAB create, config,
  list accounts/orders) + ACME protocol route dispatch
- proto/metacrypt/v1/acme.proto: ACMEService (CreateEAB, SetConfig,
  ListAccounts, ListOrders) — protocol endpoints are HTTP-only per RFC
- clients/go: new Go module with MCIAS-auth bootstrap, ACME account
  registration, certificate issuance/renewal, HTTP-01 and DNS-01
  challenge providers
- .claude/launch.json: dev server configuration

EAB is required for all account creation; MCIAS-authenticated users
obtain a single-use KID + HMAC-SHA256 key via POST /v1/acme/{mount}/eab.
2026-03-15 08:09:12 -07:00

66 lines
2.3 KiB
Go

package metacryptclient
import "time"
// HTTP01Provider handles HTTP-01 ACME challenge fulfillment.
// The caller is responsible for serving the challenge file over HTTP on port 80.
type HTTP01Provider struct {
// WriteFile is called to create the challenge response file.
// path is the URL path, e.g. "/.well-known/acme-challenge/{token}".
// content is the key authorization string to serve as the response body.
WriteFile func(path, content string) error
// RemoveFile is called after the challenge is complete (success or failure).
// path is the same path passed to WriteFile.
RemoveFile func(path string) error
}
// DNS01Provider handles DNS-01 ACME challenge fulfillment.
// The caller is responsible for managing DNS TXT records.
type DNS01Provider struct {
// SetRecord is called to create the TXT record.
// name is the fully-qualified DNS name, e.g. "_acme-challenge.example.com.".
// value is the base64url-encoded SHA-256 key authorization to set as the TXT value.
SetRecord func(name, value string) error
// RemoveRecord is called after the challenge is complete (success or failure).
// name is the same name passed to SetRecord.
RemoveRecord func(name string) error
// PropagationWait is the duration to wait after SetRecord before notifying
// the ACME server to validate. Allows time for DNS propagation.
// A value of 0 means no wait.
PropagationWait time.Duration
}
// CertificateRequest specifies what certificate to obtain.
type CertificateRequest struct {
// Domains is the list of DNS names to include as SANs.
// The first domain is used as the common name.
Domains []string
// KeyType controls the type and size of the certificate key.
// Valid values: "EC256" (default), "EC384", "RSA2048", "RSA4096".
KeyType string
// HTTP01 provides HTTP-01 challenge fulfillment. Either HTTP01 or DNS01
// (or both) must be set.
HTTP01 *HTTP01Provider
// DNS01 provides DNS-01 challenge fulfillment. Either HTTP01 or DNS01
// (or both) must be set.
DNS01 *DNS01Provider
}
// Certificate is the result of a successful ACME certificate issuance.
type Certificate struct {
// CertPEM is the PEM-encoded certificate chain (leaf + intermediates).
CertPEM []byte
// KeyPEM is the PEM-encoded private key for the certificate.
KeyPEM []byte
// ExpiresAt is the expiry time of the leaf certificate.
ExpiresAt time.Time
}