package acme import ( "crypto" "crypto/ecdsa" "crypto/elliptic" "crypto/rand" "crypto/rsa" "crypto/x509" "crypto/x509/pkix" "encoding/base64" "encoding/pem" "errors" "io" "io/ioutil" ) const ( pemRSA = `RSA PRIVATE KEY` pemEC = `EC PRIVATE KEY` pemCRT = `CERTIFICATE` ) var errKeyType = errors.New("unknown key type") 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 LoadKey(r io.Reader) (crypto.PrivateKey, error) { der, err := ioutil.ReadAll(r) if err != nil { return nil, err } block, _ := pem.Decode(der) switch block.Type { case pemRSA: return x509.ParsePKCS1PrivateKey(block.Bytes) case pemEC: return x509.ParseECPrivateKey(block.Bytes) default: return nil, errKeyType } } func SaveCert(w io.Writer, cert []byte) error { block := &pem.Block{ Type: pemCRT, Bytes: cert, } return pem.Encode(w, block) } func LoadCerts(r io.Reader) ([]*x509.Certificate, error) { der, err := ioutil.ReadAll(r) if err != nil { return nil, err } block, _ := pem.Decode(der) return x509.ParseCertificates(block.Bytes) } func NewKey(size int) (crypto.PrivateKey, error) { if size == 0 { return ecdsa.GenerateKey(elliptic.P384(), rand.Reader) } return rsa.GenerateKey(rand.Reader, size) } func NewCSR(key crypto.PrivateKey, altnames []string) (string, error) { tmpl := x509.CertificateRequest{ Subject: pkix.Name{CommonName: altnames[0]}, } if len(altnames) > 1 { tmpl.DNSNames = altnames } der, err := x509.CreateCertificateRequest(rand.Reader, &tmpl, key) if err != nil { return "", err } return base64.RawURLEncoding.EncodeToString(der), nil }