package csr import ( "crypto/rand" "crypto/x509" "crypto/x509/pkix" "encoding/pem" "fmt" "net" "os" "github.com/spf13/cobra" "src.lwithers.me.uk/go/rsa/pkg/pemfile" ) var ( outputFile string hostnames []string ips []string ) // Register the "keygen" subcommand. func Register(root *cobra.Command) { cmd := &cobra.Command{ Use: "csr key.pem \"description (common name)\"", Short: "Generate a certificate signing request", Run: CSR, Args: cobra.ExactArgs(2), } cmd.Flags().StringVarP(&outputFile, "output", "o", "", "Name of output file (defaults to stdout)") cmd.Flags().StringArrayVar(&hostnames, "host", nil, "Subject alternate name (may be specified multiple times)") cmd.Flags().StringArrayVar(&ips, "ip", nil, "IP address (may be specified multiple times)") root.AddCommand(cmd) } // CSR will load a private key, then write out and generate a CSR. func CSR(cmd *cobra.Command, args []string) { keyFile := args[0] desc := args[1] key, err := pemfile.ReadKey(keyFile) if err != nil { fmt.Fprintln(os.Stderr, err) os.Exit(1) } var ipAddrs []net.IP for _, ip := range ips { i := net.ParseIP(ip) if i == nil { fmt.Fprintf(os.Stderr, "--ip argument %q is not valid\n", ip) os.Exit(1) } ipAddrs = append(ipAddrs, i) } template := &x509.CertificateRequest{ Subject: pkix.Name{ CommonName: desc, }, DNSNames: hostnames, IPAddresses: ipAddrs, } der, err := x509.CreateCertificateRequest(rand.Reader, template, key) if err != nil { fmt.Fprintf(os.Stderr, "failed to create certificate signing request: %v\n", err) os.Exit(1) } raw := pem.EncodeToMemory(&pem.Block{ Type: pemfile.TypeX509CSR, Bytes: der, }) switch outputFile { case "", "-": os.Stdout.Write(raw) default: if err := os.WriteFile(outputFile, raw, 0600); err != nil { fmt.Fprintln(os.Stderr, err) os.Exit(1) } } }