From b4dd257d920efbae2ab1f400c08b49982593881a Mon Sep 17 00:00:00 2001 From: Dimitri Sokolyuk Date: Wed, 9 Mar 2016 23:06:31 +0100 Subject: Split stages --- cmd/acme/config.go | 20 +++--- cmd/acme/main.go | 206 ++++++++++++++++++++++++++++------------------------- desire.go | 4 +- solve_dns.go | 2 +- solve_http.go | 3 + solve_pop.go | 2 +- solve_tls.go | 3 + solver.go | 5 +- 8 files changed, 136 insertions(+), 109 deletions(-) diff --git a/cmd/acme/config.go b/cmd/acme/config.go index ebdcb76..6a0dc4b 100644 --- a/cmd/acme/config.go +++ b/cmd/acme/config.go @@ -46,12 +46,13 @@ type account struct { } type domain struct { - Altnames []string - KeySize int - KeyFile string - CrtFile string - Webroot string - Hook []string + Gracetime time.Duration + Altnames []string + KeySize int + KeyFile string + CrtFile string + Webroot string + Hook []string } var ( @@ -115,6 +116,9 @@ func LoadConfig(fname string) (*Config, error) { } pro.Account[i] = acc for i, dom := range acc.Domain { + if dom.Gracetime != 0 { + dom.Gracetime = c.Gracetime + } if dom.KeySize == 0 { dom.KeySize = c.KeySize } @@ -167,6 +171,6 @@ func checkWWW(altnames []string) []string { return altnames } -func (c Config) renew(cert *x509.Certificate) bool { - return time.Now().Add(c.Gracetime).After(cert.NotAfter) +func (d domain) renew(cert *x509.Certificate) bool { + return time.Now().Add(d.Gracetime).After(cert.NotAfter) } diff --git a/cmd/acme/main.go b/cmd/acme/main.go index e994189..577afbf 100644 --- a/cmd/acme/main.go +++ b/cmd/acme/main.go @@ -9,117 +9,129 @@ import ( ) var ( - confName = flag.String("conf", "", "configuration file") - forceRenew = flag.Bool("force", false, "force renew") + confName = flag.String("conf", "", "configuration file") + forceRenew = flag.Bool("force", false, "force renew") + httpSol, tlsSol acme.Solver ) -func main() { - flag.Parse() - - conf, err := LoadConfig(*confName) +func dialProvider(p provider) error { + log.Println("Dial", p.Directory) + prov, err := acme.DialProvider(p.Directory) if err != nil { - log.Fatal(err) + return err + } + for _, a := range p.Account { + if err := loadAccount(prov, a); err != nil { + return err + } } + return nil +} - var httpSol, tlsSol acme.Solver - if conf.Listen != "" { - httpSol, err = acme.NewHTTPSolver(conf.Listen) +func loadAccount(prov *acme.Provider, a account) error { + var mustRegister bool + key, err := a.Load() + if err != nil { + key, err = acme.NewKey(a.KeySize) if err != nil { - log.Println(err) + return err } + if err := a.Save(key); err != nil { + return err + } + mustRegister = true } - if conf.ListenTLS != "" { - tlsSol, err = acme.NewTLSSolver(conf.ListenTLS) + + acc, err := acme.NewAccount(key) + if err != nil { + return err + } + + if mustRegister { + con, err := acme.NewContacts(a.Mail, a.Phone) if err != nil { - log.Println(err) + return err + } + + log.Println("Register", con) + if err := prov.Register(acc, con); err != nil { + return err } } - for _, v := range conf.Provider { - log.Println("Dial", v.Directory) - prov, err := acme.DialProvider(v.Directory) - if err != nil { - log.Fatal(err) + for _, d := range a.Domain { + if err := requestCert(prov, acc, d); err != nil { + return err } + } + return nil +} + +func requestCert(prov *acme.Provider, acc *acme.Account, d domain) error { + c, err := d.Load() + if err != nil { + return err + } + if c.Leaf != nil && !d.renew(c.Leaf) && !*forceRenew { + log.Println("valid until", c.Leaf.NotAfter, "skip") + return nil + } + + key, err := acme.NewKey(d.KeySize) + if err != nil { + return err + } - for _, v := range v.Account { - var mustRegister bool - - log.Println("Load", v.KeyFile) - key, err := v.Load() - if err != nil { - key, err = acme.NewKey(v.KeySize) - if err != nil { - log.Fatal(err) - } - if err := v.Save(key); err != nil { - log.Fatal(err) - } - mustRegister = true - } - - acc, err := acme.NewAccount(key) - if err != nil { - log.Fatal(err) - } - - if mustRegister { - con, err := acme.NewContacts(v.Mail, v.Phone) - if err != nil { - log.Fatal(err) - } - - log.Println("Register", con) - err = prov.Register(acc, con) - if err != nil { - log.Fatal(err) - } - } - - for _, v := range v.Domain { - c, err := v.Load() - if err != nil { - log.Println(err) - } - if c.Leaf != nil && !conf.renew(c.Leaf) && !*forceRenew { - log.Println("valid until", c.Leaf.NotAfter, "sipping") - continue - } - - key, err := acme.NewKey(v.KeySize) - if err != nil { - log.Fatal(err) - } - des := acme.NewDesire(key, v.Altnames) - if v.Webroot != "" { - sol := acme.NewWebrootSolver(v.Webroot) - des.RegisterSolver(sol) - } else if httpSol != nil { - des.RegisterSolver(httpSol) - } - if tlsSol != nil { - des.RegisterSolver(tlsSol) - } - if !des.HasSolver() { - log.Fatal("no solver") - } - - log.Println("Authorize", v.Altnames) - if err := prov.Authorize(acc, des); err != nil { - log.Fatal(err) - } - - log.Println("Request bundle for", v.Altnames) - cert, err := prov.Bundle(acc, des) - if err != nil { - log.Fatal(err) - } - - log.Println("Save", v.CrtFile, v.KeyFile) - if err := v.Save(cert); err != nil { - log.Fatal(err) - } - } + des := acme.NewDesire(key, d.Altnames) + if d.Webroot != "" { + des.RegisterSolver(acme.NewWebrootSolver(d.Webroot)) + } else if httpSol != nil { + des.RegisterSolver(httpSol) + } + + if tlsSol != nil { + des.RegisterSolver(tlsSol) + } + + log.Println("Authorize", d.Altnames) + if err := prov.Authorize(acc, des); err != nil { + return err + } + + log.Println("Request bundle") + cert, err := prov.Bundle(acc, des) + if err != nil { + return err + } + + log.Println("Save", d.CrtFile, d.KeyFile) + if err := d.Save(cert); err != nil { + return err + } + + return nil +} + +func main() { + flag.Parse() + + conf, err := LoadConfig(*confName) + if err != nil { + log.Fatal(err) + } + + httpSol, err = acme.NewHTTPSolver(conf.Listen) + if err != nil { + log.Println("HTTP Solver", err) + } + tlsSol, err = acme.NewTLSSolver(conf.ListenTLS) + if err != nil { + log.Println("TLS Solver", err) + } + + for _, p := range conf.Provider { + if err := dialProvider(p); err != nil { + log.Fatal(err) } } } diff --git a/desire.go b/desire.go index 1d99433..670aca6 100644 --- a/desire.go +++ b/desire.go @@ -17,7 +17,9 @@ func NewDesire(key crypto.PrivateKey, altnames []string) *Desire { } func (d *Desire) RegisterSolver(s Solver) { - d.solver[s.Type()] = s + if s != nil { + d.solver[s.Type()] = s + } } func (d *Desire) HasSolver() bool { diff --git a/solve_dns.go b/solve_dns.go index 805ed45..a71398b 100644 --- a/solve_dns.go +++ b/solve_dns.go @@ -6,6 +6,6 @@ func NewDNSSolver() Solver { return &dnsSolver{} } -func (dnsSolver) Solve(_ Challenge) error { return errNotImplemented } +func (dnsSolver) Solve(_ Challenge) error { return ErrNotImplemented } func (dnsSolver) Solved() error { return nil } func (dnsSolver) Type() ChalType { return ChallengeDNS } diff --git a/solve_http.go b/solve_http.go index f0923a5..2b9a4a6 100644 --- a/solve_http.go +++ b/solve_http.go @@ -14,6 +14,9 @@ type httpSolver struct { } func NewHTTPSolver(addr string) (Solver, error) { + if addr == "" { + return nil, ErrSkipped + } return &httpSolver{Server: http.Server{Addr: addr}}, nil } diff --git a/solve_pop.go b/solve_pop.go index cc6dd4c..72130d0 100644 --- a/solve_pop.go +++ b/solve_pop.go @@ -6,6 +6,6 @@ func NewPOPSolver() Solver { return &popSolver{} } -func (popSolver) Solve(_ Challenge) error { return errNotImplemented } +func (popSolver) Solve(_ Challenge) error { return ErrNotImplemented } func (popSolver) Solved() error { return nil } func (popSolver) Type() ChalType { return ChallengePOP } diff --git a/solve_tls.go b/solve_tls.go index babc5e4..8dbf496 100644 --- a/solve_tls.go +++ b/solve_tls.go @@ -29,6 +29,9 @@ func (s *tlsSolver) getCert(h *tls.ClientHelloInfo) (*tls.Certificate, error) { } func NewTLSSolver(addr string) (Solver, error) { + if addr == "" { + return nil, ErrSkipped + } // we need at least one cert dummy, err := newCert("dummy" + AcmeInvalid) if err != nil { diff --git a/solver.go b/solver.go index 33e8493..8671f21 100644 --- a/solver.go +++ b/solver.go @@ -2,7 +2,10 @@ package acme import "errors" -var errNotImplemented = errors.New("not implemented") +var ( + ErrNotImplemented = errors.New("not implemented") + ErrSkipped = errors.New("solver skipped") +) // WellKnown URL path const WellKnown = `/.well-known/acme-challenge/` -- cgit v1.2.3