package acme import ( "crypto/rand" "crypto/rsa" "crypto/tls" "crypto/x509" "crypto/x509/pkix" "encoding/base64" ) type Desire struct { cert tls.Certificate altnames []string 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{ cert: tls.Certificate{PrivateKey: 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 (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.cert.PrivateKey) if err != nil { return "", err } return base64.RawURLEncoding.EncodeToString(der), nil } func (d *Desire) LoadKeyPair(certFile, keyFile string) (err error) { d.cert, err = tls.LoadX509KeyPair(certFile, keyFile) return } func (d *Desire) SaveKeyPair(certFile, keyFile string) error { if err := d.saveKey(keyFile); err != nil { return err } return d.saveCert(certFile) } func (d *Desire) saveKey(fname string) error { fd, err := CreateFile(fname, 0600) if err != nil { return err } defer fd.Close() return SaveKey(fd, d.cert.PrivateKey) } func (d *Desire) saveCert(fname string) error { fd, err := CreateFile(fname, 0644) if err != nil { return err } defer fd.Close() for _, crt := range d.cert.Certificate { if err := saveCert(fd, crt); err != nil { return err } } return nil }