rsa/cmd/csr/csr.go

88 lines
1.8 KiB
Go

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)
}
}
}