From cf49d970245fdd871a85c9393a54bdefcbdfc39a Mon Sep 17 00:00:00 2001 From: Dimitri Sokolyuk Date: Sun, 6 Mar 2016 02:26:20 +0100 Subject: Move file handling out of the lib --- account.go | 37 +------------------------------- cmd/acme/fs.go | 64 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++ cmd/acme/main.go | 27 ++++++++++++------------ crypto.go | 62 +++++++++++++++++++----------------------------------- desire.go | 33 +++-------------------------- solve_tls.go | 2 +- solve_webroot.go | 10 ++------- 7 files changed, 107 insertions(+), 128 deletions(-) create mode 100644 cmd/acme/fs.go diff --git a/account.go b/account.go index a5a3886..7ac6089 100644 --- a/account.go +++ b/account.go @@ -3,8 +3,6 @@ package acme import ( "crypto" "crypto/ecdsa" - "crypto/elliptic" - "crypto/rand" "crypto/rsa" "encoding/base64" "io" @@ -22,31 +20,7 @@ type Account struct { signer jose.Signer } -func LoadAccount(fname string) (*Account, error) { - key, err := LoadKeyFile(fname) - if err != nil { - return nil, err - } - return newAccount(key) -} - -func NewAccount(size int) (*Account, error) { - key, err := rsa.GenerateKey(rand.Reader, size) - if err != nil { - return nil, err - } - return newAccount(key) -} - -func NewAccountEC() (*Account, error) { - key, err := ecdsa.GenerateKey(elliptic.P384(), rand.Reader) - if err != nil { - return nil, err - } - return newAccount(key) -} - -func newAccount(key crypto.PrivateKey) (*Account, error) { +func NewAccount(key crypto.PrivateKey) (*Account, error) { switch k := key.(type) { case *rsa.PrivateKey: signer, err := jose.NewSigner(jose.RS256, k) @@ -89,12 +63,3 @@ func (a *Account) KeyAuth(token string) (string, error) { } return token + "." + base64.RawURLEncoding.EncodeToString(thumb), nil } - -func (a *Account) Save(fname string) error { - fd, err := CreateFile(fname, 0600) - if err != nil { - return err - } - defer fd.Close() - return SaveKey(fd, a.key) -} diff --git a/cmd/acme/fs.go b/cmd/acme/fs.go new file mode 100644 index 0000000..4f8c479 --- /dev/null +++ b/cmd/acme/fs.go @@ -0,0 +1,64 @@ +package main + +import ( + "crypto" + "crypto/tls" + "io" + "os" + "syscall" + + "dim13.org/acme" +) + +func NewFile(fname string, mode os.FileMode) (io.WriteCloser, error) { + err := os.Rename(fname, fname+".bak") + if nerr, ok := err.(*os.LinkError); ok && nerr.Err != syscall.ENOENT { + return nil, err + } + flags := os.O_WRONLY | os.O_CREATE | os.O_TRUNC + return os.OpenFile(fname, flags, mode) +} + +func (d domain) Save(cert tls.Certificate) error { + // save key + fd, err := NewFile(d.KeyFile, 0600) + if err != nil { + return err + } + defer fd.Close() + err = acme.SaveKey(fd, cert.PrivateKey) + if err != nil { + return err + } + + // save certs + fd, err = NewFile(d.CrtFile, 0644) + if err != nil { + return err + } + defer fd.Close() + for _, crt := range cert.Certificate { + if err := acme.SaveCert(fd, crt); err != nil { + return err + } + } + return nil +} + +func (a account) Save(key crypto.PrivateKey) error { + fd, err := NewFile(a.KeyFile, 0600) + if err != nil { + return err + } + defer fd.Close() + return acme.SaveKey(fd, key) +} + +func (a account) Load() (crypto.PrivateKey, error) { + fd, err := os.Open(a.KeyFile) + if err != nil { + return nil, err + } + defer fd.Close() + return acme.LoadKey(fd) +} diff --git a/cmd/acme/main.go b/cmd/acme/main.go index 721d204..50855d9 100644 --- a/cmd/acme/main.go +++ b/cmd/acme/main.go @@ -41,10 +41,22 @@ func main() { for _, v := range v.Account { log.Println("Load", v.KeyFile) - acc, err := getAccount(v.KeyFile, v.KeySize) + 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) + } + + acc, err := acme.NewAccount(key) if err != nil { log.Fatal(err) } + con := acme.Contacts{} con.AddMail(v.Mail) con.AddPhone(v.Phone) @@ -84,21 +96,10 @@ func main() { } log.Println("Save", v.CrtFile, v.KeyFile) - if err := des.SaveKeyPair(v.CrtFile, v.KeyFile); err != nil { + if err := v.Save(des.Cert()); err != nil { log.Fatal(err) } } } } } - -func getAccount(keyFile string, keySize int) (*acme.Account, error) { - acc, err := acme.LoadAccount(keyFile) - if err != nil { - acc, err = acme.NewAccount(keySize) - if err != nil { - return nil, err - } - } - return acc, acc.Save(keyFile) -} diff --git a/crypto.go b/crypto.go index 5ed81c0..eb859c2 100644 --- a/crypto.go +++ b/crypto.go @@ -3,14 +3,14 @@ package acme import ( "crypto" "crypto/ecdsa" + "crypto/elliptic" + "crypto/rand" "crypto/rsa" "crypto/x509" "encoding/pem" "errors" "io" "io/ioutil" - "os" - "syscall" ) const ( @@ -21,13 +21,20 @@ const ( var errKeyType = errors.New("unknown key type") -func LoadKeyFile(fname string) (crypto.PrivateKey, error) { - fd, err := os.Open(fname) - if err != nil { - return nil, err +func SaveKey(w io.Writer, key crypto.PrivateKey) error { + var block *pem.Block + switch k := key.(type) { + case *rsa.PrivateKey: + der := x509.MarshalPKCS1PrivateKey(k) + block = &pem.Block{Type: pemRSA, Bytes: der} + case *ecdsa.PrivateKey: + der, err := x509.MarshalECPrivateKey(k) + if err != nil { + return err + } + block = &pem.Block{Type: pemEC, Bytes: der} } - defer fd.Close() - return LoadKey(fd) + return pem.Encode(w, block) } func LoadKey(r io.Reader) (crypto.PrivateKey, error) { @@ -46,23 +53,7 @@ func LoadKey(r io.Reader) (crypto.PrivateKey, error) { } } -func SaveKey(w io.Writer, key crypto.PrivateKey) error { - var block *pem.Block - switch k := key.(type) { - case *rsa.PrivateKey: - der := x509.MarshalPKCS1PrivateKey(k) - block = &pem.Block{Type: pemRSA, Bytes: der} - case *ecdsa.PrivateKey: - der, err := x509.MarshalECPrivateKey(k) - if err != nil { - return err - } - block = &pem.Block{Type: pemEC, Bytes: der} - } - return pem.Encode(w, block) -} - -func saveCert(w io.Writer, cert []byte) error { +func SaveCert(w io.Writer, cert []byte) error { block := &pem.Block{ Type: pemCRT, Bytes: cert, @@ -70,15 +61,6 @@ func saveCert(w io.Writer, cert []byte) error { return pem.Encode(w, block) } -func LoadCertFile(fname string) ([]*x509.Certificate, error) { - fd, err := os.Open(fname) - if err != nil { - return nil, err - } - defer fd.Close() - return LoadCerts(fd) -} - func LoadCerts(r io.Reader) ([]*x509.Certificate, error) { der, err := ioutil.ReadAll(r) if err != nil { @@ -88,11 +70,11 @@ func LoadCerts(r io.Reader) ([]*x509.Certificate, error) { return x509.ParseCertificates(block.Bytes) } -func CreateFile(fname string, mode os.FileMode) (io.WriteCloser, error) { - err := os.Rename(fname, fname+".bak") - if nerr, ok := err.(*os.LinkError); ok && nerr.Err != syscall.ENOENT { - return nil, nerr +func NewKey(size int) (crypto.PrivateKey, error) { + switch size { + case 0: + return ecdsa.GenerateKey(elliptic.P384(), rand.Reader) + default: + return rsa.GenerateKey(rand.Reader, size) } - flags := os.O_WRONLY | os.O_CREATE | os.O_TRUNC - return os.OpenFile(fname, flags, mode) } diff --git a/desire.go b/desire.go index 4e7392a..148523f 100644 --- a/desire.go +++ b/desire.go @@ -2,7 +2,6 @@ package acme import ( "crypto/rand" - "crypto/rsa" "crypto/tls" "crypto/x509" "crypto/x509/pkix" @@ -16,7 +15,7 @@ type Desire struct { } func NewDesire(altnames []string, size int) (*Desire, error) { - key, err := rsa.GenerateKey(rand.Reader, size) + key, err := NewKey(size) if err != nil { return nil, err } @@ -54,32 +53,6 @@ func (d *Desire) LoadKeyPair(certFile, keyFile string) (err error) { 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 +func (d *Desire) Cert() tls.Certificate { + return d.cert } diff --git a/solve_tls.go b/solve_tls.go index 4e376c1..36bbf11 100644 --- a/solve_tls.go +++ b/solve_tls.go @@ -55,7 +55,7 @@ func newCert(domain string) (tls.Certificate, error) { fail := func(err error) (tls.Certificate, error) { return tls.Certificate{}, err } - key, err := rsa.GenerateKey(rand.Reader, 2048) + key, err := rsa.GenerateKey(rand.Reader, 2048) // NewKey(2048) if err != nil { return fail(err) } diff --git a/solve_webroot.go b/solve_webroot.go index 096ca4a..12720f3 100644 --- a/solve_webroot.go +++ b/solve_webroot.go @@ -1,7 +1,7 @@ package acme import ( - "io" + "io/ioutil" "log" "os" "path" @@ -23,13 +23,7 @@ func (s *webrootSolver) Solve(ch Challenge) error { if err != nil { return err } - fd, err := CreateFile(s.file, 0644) - if err != nil { - return err - } - defer fd.Close() - _, err = io.WriteString(fd, ch.KeyAuthorization) - return err + return ioutil.WriteFile(s.file, []byte(ch.KeyAuthorization), 0644) } func (s *webrootSolver) Solved() error { -- cgit v1.2.3