package acme import ( "crypto" "crypto/rand" "crypto/rsa" "crypto/x509" "crypto/x509/pkix" "encoding/base64" "os" "syscall" ) type Desire struct { altnames []string key crypto.PrivateKey cert []*x509.Certificate solver map[ChalType]Solver } func NewDesire(altnames []string, size int) (*Desire, error) { key, err := rsa.GenerateKey(rand.Reader, size) if err != nil { return nil, err } return &Desire{ key: key, altnames: altnames, solver: make(map[ChalType]Solver), }, nil } func (d *Desire) RegisterSolver(s Solver) { d.solver[s.Type()] = s } func (d *Desire) HasSolver() bool { return len(d.solver) > 0 } func backup(fname string) error { err := os.Rename(fname, fname+".bak") if nerr, ok := err.(*os.LinkError); ok && nerr.Err == syscall.ENOENT { return nil } return err } func (d *Desire) Save(cert, key string) error { if err := d.saveKey(key); err != nil { return err } return d.saveCert(cert) } func (d *Desire) saveKey(fname string) error { if err := backup(fname); err != nil { return err } fd, err := CreatePrivFile(fname) if err != nil { return err } defer fd.Close() return saveKey(fd, d.key) } func (d *Desire) saveCert(fname string) error { if err := backup(fname); err != nil { return err } fd, err := CreatePubFile(fname) if err != nil { return err } defer fd.Close() for _, crt := range d.cert { if err := saveCert(fd, crt); err != nil { return err } } return nil } func (d *Desire) CSR() (string, error) { tmpl := x509.CertificateRequest{ Subject: pkix.Name{CommonName: d.altnames[0]}, } if len(d.altnames) > 1 { tmpl.DNSNames = d.altnames } der, err := x509.CreateCertificateRequest(rand.Reader, &tmpl, d.key) if err != nil { return "", err } return base64.RawURLEncoding.EncodeToString(der), nil }