diff --git a/cert/cert.go b/cert/cert.go index 92dd483..3c29762 100644 --- a/cert/cert.go +++ b/cert/cert.go @@ -7,6 +7,7 @@ import ( "crypto/x509/pkix" "encoding/pem" "math/big" + "net" "os" "path" "time" @@ -35,65 +36,142 @@ func (c *Cert) GenerateSelfSignedCert() error { return nil } - priv, err := rsa.GenerateKey(rand.Reader, 2048) + caCert, caKey, err := createCA() if err != nil { return err } - serialNumber, _ := rand.Int(rand.Reader, big.NewInt(1<<62)) - - template := x509.Certificate{ - SerialNumber: serialNumber, - Subject: pkix.Name{ - CommonName: "localhost", - Organization: []string{c.Organization}, - }, - NotBefore: time.Now(), - NotAfter: time.Now().Add(365 * 24 * time.Hour), - - KeyUsage: x509.KeyUsageKeyEncipherment | x509.KeyUsageDigitalSignature, - ExtKeyUsage: []x509.ExtKeyUsage{x509.ExtKeyUsageServerAuth}, - BasicConstraintsValid: true, - DNSNames: []string{"localhost"}, - } - - certDER, err := x509.CreateCertificate(rand.Reader, &template, &template, &priv.PublicKey, priv) + serverCert, serverKey, err := createServerCert(caCert, caKey) if err != nil { return err } - if _, err := os.Stat(path.Dir(c.CertFile)); os.IsNotExist(err) { - os.MkdirAll(path.Dir(c.CertFile), 0700) - } - - certOut, err := os.Create(c.CertFile) - if err != nil { - return err - } - defer certOut.Close() - pem.Encode(certOut, &pem.Block{Type: "CERTIFICATE", Bytes: certDER}) - - // Set permission to 0600 (read/write by owner only) - if err := os.Chmod(c.CertFile, 0600); err != nil { + if err := os.MkdirAll(path.Dir(c.CertFile), 0700); err != nil { return err } - if _, err := os.Stat(path.Dir(c.KeyFile)); os.IsNotExist(err) { - os.MkdirAll(path.Dir(c.KeyFile), 0700) - } - - keyOut, err := os.Create(c.KeyFile) - if err != nil { + if err := os.MkdirAll(path.Dir(c.KeyFile), 0700); err != nil { return err } - defer keyOut.Close() - pem.Encode(keyOut, &pem.Block{Type: "RSA PRIVATE KEY", Bytes: x509.MarshalPKCS1PrivateKey(priv)}) + if err := saveCert(c.CertFile, serverCert.Raw); err != nil { + return err + } - // Set permission to 0600 (read/write by owner only) - if err := os.Chmod(c.KeyFile, 0600); err != nil { + 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) +} diff --git a/test/dbm_test.go b/test/dbm_test.go index a03f9e1..59a4eef 100644 --- a/test/dbm_test.go +++ b/test/dbm_test.go @@ -3,6 +3,7 @@ package test import ( "fmt" "math/rand" + "os" "runtime" "testing" "time" @@ -146,3 +147,30 @@ func TestServer(t *testing.T) { t.Fatal(server.ServeHttp("http://localhost", 8100)) } + +func TestCreateCerts(t *testing.T) { + certFile := "cert.pem" + keyFile := "key.pem" + + defer func() { + err := os.Remove(certFile) + if err != nil { + t.Fatal(err) + } + err = os.Remove(keyFile) + if err != nil { + t.Fatal(err) + } + }() + + t.Log("test create certificates") + cert := cert.Cert{ + Organization: "tecamino", + CertFile: certFile, + KeyFile: keyFile, + } + + if err := cert.GenerateSelfSignedCert(); err != nil { + t.Fatal(err) + } +}