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.
This commit is contained in:
65
clients/go/challenge.go
Normal file
65
clients/go/challenge.go
Normal file
@@ -0,0 +1,65 @@
|
||||
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
|
||||
}
|
||||
Reference in New Issue
Block a user