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.
66 lines
2.3 KiB
Go
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
|
|
}
|