package cert import ( "crypto/rand" "crypto/rsa" "crypto/x509" "crypto/x509/pkix" "encoding/pem" "math/big" "net" "os" "path" "time" ) type Cert struct { Organization string CertFile string KeyFile string } // Initialize a new ssl certificate handler with organization name func NewCertHandler(org string) *Cert { return &Cert{ Organization: org, } } // generates a new self signed ssl certificate foe localhost and development use func (c *Cert) GenerateSelfSignedCert() error { // do not generate certs if they exist _, err := os.Stat(c.CertFile) _, err2 := os.Stat(c.KeyFile) if !os.IsNotExist(err) && !os.IsNotExist(err2) { return nil } caCert, caKey, err := createCA() if err != nil { return err } serverCert, serverKey, err := createServerCert(caCert, caKey) if err != nil { return err } if err := os.MkdirAll(path.Dir(c.CertFile), 0700); err != nil { return err } if err := os.MkdirAll(path.Dir(c.KeyFile), 0700); err != nil { return err } if err := saveCert(c.CertFile, serverCert.Raw); err != nil { return err } if err := saveKey(c.KeyFile, serverKey); err != nil { return err } return nil } func createCA() (*x509.Certificate, *rsa.PrivateKey, error) { priv, _ := rsa.GenerateKey(rand.Reader, 2048) serial, _ := rand.Int(rand.Reader, big.NewInt(1<<62)) template := x509.Certificate{ SerialNumber: serial, Subject: pkix.Name{ CommonName: "Local Dev CA", }, NotBefore: time.Now(), NotAfter: time.Now().AddDate(10, 0, 0), KeyUsage: x509.KeyUsageCertSign | x509.KeyUsageCRLSign, BasicConstraintsValid: true, IsCA: true, } certDER, _ := x509.CreateCertificate( rand.Reader, &template, &template, &priv.PublicKey, priv, ) cert, _ := x509.ParseCertificate(certDER) return cert, priv, nil } func createServerCert( ca *x509.Certificate, caKey *rsa.PrivateKey, ) (*x509.Certificate, *rsa.PrivateKey, error) { priv, _ := rsa.GenerateKey(rand.Reader, 2048) serial, _ := rand.Int(rand.Reader, big.NewInt(1<<62)) template := x509.Certificate{ SerialNumber: serial, Subject: pkix.Name{ CommonName: "localhost", }, NotBefore: time.Now(), NotAfter: time.Now().AddDate(1, 0, 0), KeyUsage: x509.KeyUsageDigitalSignature, ExtKeyUsage: []x509.ExtKeyUsage{x509.ExtKeyUsageServerAuth}, DNSNames: []string{ "localhost", "lvh.me", }, IPAddresses: []net.IP{ net.ParseIP("127.0.0.1"), net.ParseIP("::1"), }, } certDER, _ := x509.CreateCertificate( rand.Reader, &template, ca, &priv.PublicKey, caKey, ) cert, _ := x509.ParseCertificate(certDER) return cert, priv, nil } func saveCert(path string, der []byte) error { file, err := os.Create(path) if err != nil { return err } defer file.Close() if err := pem.Encode(file, &pem.Block{ Type: "CERTIFICATE", Bytes: der, }); err != nil { return err } return os.Chmod(path, 0600) } func saveKey(path string, key *rsa.PrivateKey) error { file, err := os.Create(path) if err != nil { return err } defer file.Close() if err := pem.Encode(file, &pem.Block{ Type: "RSA PRIVATE KEY", Bytes: x509.MarshalPKCS1PrivateKey(key), }); err != nil { return err } return os.Chmod(path, 0600) }