The current generate_cert helper was originally taken from Go's source, and is more complex than we need it to be. This patch replaces it with our own version, rewritten from scratch independently.
130 lines
3.0 KiB
Go
130 lines
3.0 KiB
Go
//go:build !coverage
|
|
// +build !coverage
|
|
|
|
// Utility to generate self-signed certificates.
|
|
// It generates a self-signed x509 certificate and key pair, and writes them
|
|
// to "fullchain.pem" and "privkey.pem".
|
|
//
|
|
// Intended for use in tests, not for production use.
|
|
package main
|
|
|
|
import (
|
|
crand "crypto/rand"
|
|
"crypto/rsa"
|
|
"crypto/x509"
|
|
"crypto/x509/pkix"
|
|
"encoding/pem"
|
|
"flag"
|
|
"fmt"
|
|
"math/big"
|
|
"net"
|
|
"os"
|
|
"strings"
|
|
"time"
|
|
|
|
"golang.org/x/net/idna"
|
|
)
|
|
|
|
var (
|
|
host = flag.String("host", "",
|
|
"Hostnames/IPs to generate the certificate for (comma separated)")
|
|
validFor = flag.Duration("validfor", 4*time.Hour,
|
|
"How long will the certificate be valid for")
|
|
isCA = flag.Bool("ca", false,
|
|
"Should this cert be its own CA?")
|
|
)
|
|
|
|
func fatalf(f string, a ...interface{}) {
|
|
fmt.Printf(f, a...)
|
|
os.Exit(1)
|
|
}
|
|
|
|
func main() {
|
|
flag.Parse()
|
|
if *host == "" {
|
|
fatalf("Required flag: --host")
|
|
}
|
|
|
|
// Build the certificate template.
|
|
serial, err := crand.Int(crand.Reader, big.NewInt(1<<62))
|
|
if err != nil {
|
|
fatalf("Error generating serial number: %v\n", err)
|
|
}
|
|
tmpl := x509.Certificate{
|
|
SerialNumber: serial,
|
|
Subject: pkix.Name{Organization: []string{"Test Cert Org"}},
|
|
|
|
// Valid from now until `--validfor` in the future.
|
|
// Extended certs can be useful for manual troubleshooting.
|
|
NotBefore: time.Now(),
|
|
NotAfter: time.Now().Add(*validFor),
|
|
|
|
KeyUsage: x509.KeyUsageKeyEncipherment |
|
|
x509.KeyUsageDigitalSignature |
|
|
x509.KeyUsageCertSign,
|
|
ExtKeyUsage: []x509.ExtKeyUsage{x509.ExtKeyUsageServerAuth},
|
|
|
|
BasicConstraintsValid: true,
|
|
}
|
|
|
|
if *isCA {
|
|
tmpl.IsCA = true
|
|
}
|
|
|
|
hosts := strings.Split(*host, ",")
|
|
for _, h := range hosts {
|
|
if ip := net.ParseIP(h); ip != nil {
|
|
tmpl.IPAddresses = append(tmpl.IPAddresses, ip)
|
|
} else {
|
|
// We use IDNA-encoded DNS names, otherwise the TLS library won't
|
|
// load the certificates.
|
|
ih, err := idna.ToASCII(h)
|
|
if err != nil {
|
|
fatalf("Host %q cannot be IDNA-encoded: %v\n", h, err)
|
|
}
|
|
tmpl.DNSNames = append(tmpl.DNSNames, ih)
|
|
}
|
|
}
|
|
|
|
// Generate a private key (RSA 2048).
|
|
privK, err := rsa.GenerateKey(crand.Reader, 2048)
|
|
if err != nil {
|
|
fatalf("Error generating key: %v\n", err)
|
|
}
|
|
|
|
// Write the certificate.
|
|
{
|
|
derBytes, err := x509.CreateCertificate(
|
|
crand.Reader, &tmpl, &tmpl, &privK.PublicKey, privK)
|
|
if err != nil {
|
|
fatalf("Failed to create certificate: %v\n", err)
|
|
}
|
|
|
|
fullchain, err := os.Create("fullchain.pem")
|
|
if err != nil {
|
|
fatalf("Failed to open fullchain.pem: %v\n", err)
|
|
}
|
|
err = pem.Encode(fullchain,
|
|
&pem.Block{Type: "CERTIFICATE", Bytes: derBytes})
|
|
if err != nil {
|
|
fatalf("Error encoding certificate: %v\n", err)
|
|
}
|
|
fullchain.Close()
|
|
}
|
|
|
|
// Write the private key.
|
|
{
|
|
privkey, err := os.Create("privkey.pem")
|
|
if err != nil {
|
|
fatalf("failed to open privkey.pem: %v\n", err)
|
|
}
|
|
block := &pem.Block{Type: "RSA PRIVATE KEY",
|
|
Bytes: x509.MarshalPKCS1PrivateKey(privK)}
|
|
err = pem.Encode(privkey, block)
|
|
if err != nil {
|
|
fatalf("Error encoding private key: %v\n", err)
|
|
}
|
|
privkey.Close()
|
|
}
|
|
}
|