package acme import ( "context" "crypto/rand" "encoding/base64" "encoding/json" "fmt" "strings" "time" ) // CreateEAB generates a new EAB credential for the given MCIAS user. // The credential is stored in the barrier and must be consumed on first use. func (h *Handler) CreateEAB(ctx context.Context, mciasUsername string) (*EABCredential, error) { kidBytes := make([]byte, 16) if _, err := rand.Read(kidBytes); err != nil { return nil, fmt.Errorf("acme: generate EAB kid: %w", err) } hmacKey := make([]byte, 32) if _, err := rand.Read(hmacKey); err != nil { return nil, fmt.Errorf("acme: generate EAB key: %w", err) } cred := &EABCredential{ KID: base64.RawURLEncoding.EncodeToString(kidBytes), HMACKey: hmacKey, Used: false, CreatedBy: mciasUsername, CreatedAt: time.Now(), } data, err := json.Marshal(cred) if err != nil { return nil, fmt.Errorf("acme: marshal EAB: %w", err) } path := h.barrierPrefix() + "eab/" + cred.KID + ".json" if err := h.barrier.Put(ctx, path, data); err != nil { return nil, fmt.Errorf("acme: store EAB: %w", err) } return cred, nil } // GetEAB retrieves an EAB credential by KID. func (h *Handler) GetEAB(ctx context.Context, kid string) (*EABCredential, error) { path := h.barrierPrefix() + "eab/" + kid + ".json" data, err := h.barrier.Get(ctx, path) if err != nil || data == nil { return nil, fmt.Errorf("acme: EAB not found") } var cred EABCredential if err := json.Unmarshal(data, &cred); err != nil { return nil, fmt.Errorf("acme: unmarshal EAB: %w", err) } return &cred, nil } // MarkEABUsed marks an EAB credential as consumed so it cannot be reused. func (h *Handler) MarkEABUsed(ctx context.Context, kid string) error { cred, err := h.GetEAB(ctx, kid) if err != nil { return err } cred.Used = true data, err := json.Marshal(cred) if err != nil { return fmt.Errorf("acme: marshal EAB: %w", err) } return h.barrier.Put(ctx, h.barrierPrefix()+"eab/"+kid+".json", data) } // ListAccounts returns all ACME accounts for this mount. func (h *Handler) ListAccounts(ctx context.Context) ([]*Account, error) { paths, err := h.barrier.List(ctx, h.barrierPrefix()+"accounts/") if err != nil { return nil, err } var accounts []*Account for _, p := range paths { if !strings.HasSuffix(p, ".json") { continue } data, err := h.barrier.Get(ctx, h.barrierPrefix()+"accounts/"+p) if err != nil || data == nil { continue } var acc Account if err := json.Unmarshal(data, &acc); err != nil { continue } accounts = append(accounts, &acc) } return accounts, nil } // ListOrders returns all ACME orders for this mount. func (h *Handler) ListOrders(ctx context.Context) ([]*Order, error) { paths, err := h.barrier.List(ctx, h.barrierPrefix()+"orders/") if err != nil { return nil, err } var orders []*Order for _, p := range paths { if !strings.HasSuffix(p, ".json") { continue } data, err := h.barrier.Get(ctx, h.barrierPrefix()+"orders/"+p) if err != nil || data == nil { continue } var order Order if err := json.Unmarshal(data, &order); err != nil { continue } orders = append(orders, &order) } return orders, nil }