// adopted from https://golang.org/src/crypto/tls/generate_cert.go?m=text // Generate a self-signed X.509 certificate for a TLS server. package testcert import ( "crypto/ecdsa" "crypto/elliptic" "crypto/rand" "crypto/rsa" "crypto/x509" "crypto/x509/pkix" "encoding/pem" "errors" "fmt" "log" "math/big" "net" "os" "strings" "time" ) /* var ( host = flag.String("host", "", "Comma-separated hostnames and IPs to generate a certificate for") validFrom = flag.String("start-date", "", "Creation date formatted as Jan 1 15:04:05 2011") validFor = flag.Duration("duration", 365*24*time.Hour, "Duration that certificate is valid for") isCA = flag.Bool("ca", false, "whether this cert should be its own Certificate Authority") rsaBits = flag.Int("rsa-bits", 2048, "Size of RSA key to generate. Ignored if --ecdsa-curve is set") ecdsaCurve = flag.String("ecdsa-curve", "", "ECDSA curve to use to generate a key. Valid values are P224, P256, P384, P521") ) */ func publicKey(priv interface{}) interface{} { switch k := priv.(type) { case *rsa.PrivateKey: return &k.PublicKey case *ecdsa.PrivateKey: return &k.PublicKey default: return nil } } func pemBlockForKey(priv interface{}) (*pem.Block, error) { switch k := priv.(type) { case *rsa.PrivateKey: return &pem.Block{Type: "RSA PRIVATE KEY", Bytes: x509.MarshalPKCS1PrivateKey(k)}, nil case *ecdsa.PrivateKey: b, err := x509.MarshalECPrivateKey(k) if err != nil { err = errors.New(fmt.Sprintf("Unable to marshal ECDSA private key: %v", err)) } return &pem.Block{Type: "EC PRIVATE KEY", Bytes: b}, err default: return nil, errors.New("not a private key") } } // validFrom - Creation date formatted as Jan 1 15:04:05 2011 or "" func GenerateCert(host string, validFrom string, validFor time.Duration, isCA bool, rsaBits int, ecdsaCurve string, dirPrefix string) (err error) { if len(host) == 0 { log.Fatalf("Missing required --host parameter") } var priv interface{} switch ecdsaCurve { case "": priv, err = rsa.GenerateKey(rand.Reader, rsaBits) case "P224": priv, err = ecdsa.GenerateKey(elliptic.P224(), rand.Reader) case "P256": priv, err = ecdsa.GenerateKey(elliptic.P256(), rand.Reader) case "P384": priv, err = ecdsa.GenerateKey(elliptic.P384(), rand.Reader) case "P521": priv, err = ecdsa.GenerateKey(elliptic.P521(), rand.Reader) default: err = errors.New(fmt.Sprintf("Unrecognized elliptic curve: %q", ecdsaCurve)) } if err != nil { log.Fatalf("failed to generate private key: %s", err) return } var notBefore time.Time if len(validFrom) == 0 { notBefore = time.Now() } else { notBefore, err = time.Parse("Jan 2 15:04:05 2006", validFrom) if err != nil { err = errors.New(fmt.Sprintf("Failed to parse creation date: %s\n", err)) return } } notAfter := notBefore.Add(validFor) serialNumberLimit := new(big.Int).Lsh(big.NewInt(1), 128) serialNumber, err := rand.Int(rand.Reader, serialNumberLimit) if err != nil { log.Fatalf("failed to generate serial number: %s", err) } template := x509.Certificate{ SerialNumber: serialNumber, Subject: pkix.Name{ Organization: []string{"Acme Co"}, }, NotBefore: notBefore, NotAfter: notAfter, KeyUsage: x509.KeyUsageKeyEncipherment | x509.KeyUsageDigitalSignature, ExtKeyUsage: []x509.ExtKeyUsage{x509.ExtKeyUsageServerAuth}, BasicConstraintsValid: true, } hosts := strings.Split(host, ",") for _, h := range hosts { if ip := net.ParseIP(h); ip != nil { template.IPAddresses = append(template.IPAddresses, ip) } else { template.DNSNames = append(template.DNSNames, h) } } if isCA { template.IsCA = true template.KeyUsage |= x509.KeyUsageCertSign } derBytes, err := x509.CreateCertificate(rand.Reader, &template, &template, publicKey(priv), priv) if err != nil { log.Fatalf("Failed to create certificate: %s", err) } certOut, err := os.Create(dirPrefix + host + ".cert.pem") if err != nil { log.Fatalf("failed to open cert.pem for writing: %s", err) } err = pem.Encode(certOut, &pem.Block{Type: "CERTIFICATE", Bytes: derBytes}) if err != nil { return } if err = certOut.Sync(); err != nil { return } if err = certOut.Close(); err != nil { return } keyOut, err := os.OpenFile(dirPrefix+host+".key.pem", os.O_WRONLY|os.O_CREATE|os.O_TRUNC, 0600) if err != nil { log.Print("failed to open key.pem for writing:", err) return } var block *pem.Block if block, err = pemBlockForKey(priv); err != nil { return err } if err = pem.Encode(keyOut, block); err != nil { return err } if err = keyOut.Sync(); err != nil { return err } if err = keyOut.Close(); err != nil { return err } return }