// ACME CLI tool package main import ( "crypto" "flag" "fmt" "log" "time" "dim13.org/acme" ) var ( confName = flag.String("conf", "acme.yml", "configuration file") forceRenew = flag.Bool("force", false, "force renew") dumpConfig = flag.Bool("dump", false, "dump parsed configuration") httpSol, tlsSol acme.Solver ) func register(d desire, dir string) (crypto.PrivateKey, error) { key, err := acme.NewKey(d.KeySize) if err != nil { return nil, err } defer d.Save(key) con, err := acme.NewContacts(d.Mail, d.Phone) if err != nil { return nil, err } agree := func(tos string) bool { log.Println("agree to", tos) return true } log.Println("Dial") prov, err := acme.DialProvider(dir, key) if err != nil { return nil, err } log.Println("Register", con) if err := prov.Register(con, agree); err != nil { return nil, err } return key, nil } func requestCert(prov *acme.Provider, d domain, mail string) error { c, err := d.Load() if err != nil { c.PrivateKey, err = acme.NewKey(d.KeySize) if err != nil { return err } } skipValid := func() bool { if c.Leaf == nil || *forceRenew { return false } return time.Now().Add(d.Gracetime).Before(c.Leaf.NotAfter) } if skipValid() { log.Println("skip valid until", c.Leaf.NotAfter) return nil } sols := acme.NewSolvers() if d.Webroot != "" { sols.Add(acme.NewWebrootSolver(d.Webroot)) } else { sols.Add(httpSol) sols.Add(tlsSol) } for _, alt := range d.Altnames { log.Println("Authorize", alt) if err := prov.Authorize(sols, alt); err != nil { return err } } log.Println("Request bundle for", d.Altnames) cert, err := prov.Bundle(c.PrivateKey, d.Altnames, mail) 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) } if *dumpConfig { out, err := conf.dump() if err != nil { log.Fatal(err) } fmt.Println(string(out)) return } 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 _, d := range conf.Desire { key, err := d.Load() if err != nil { if key, err = register(d, conf.Directory); err != nil { log.Fatal(err) } } log.Println("Dial", conf.Directory) prov, err := acme.DialProvider(conf.Directory, key) if err != nil { log.Fatal(err) } for _, dom := range d.Domain { if err := requestCert(prov, dom, d.Mail); err != nil { log.Fatal(err) } } } }