rsa/cmd/ca/sign.go

92 lines
1.9 KiB
Go
Raw Normal View History

package ca
import (
"crypto/rsa"
"crypto/x509"
"encoding/pem"
"fmt"
"os"
"path/filepath"
"time"
"github.com/spf13/cobra"
"src.lwithers.me.uk/go/rsa/pkg/ca"
"src.lwithers.me.uk/go/rsa/pkg/pemfile"
)
// Sign one or more CSRs.
func Sign(cmd *cobra.Command, args []string) {
csrFilename := args[0]
from, until := signingDates(365 * 24 * time.Hour)
// open the CA
ca, err := ca.Open(dir)
if err != nil {
fmt.Fprintln(os.Stderr, err)
os.Exit(1)
}
// parse the CSR
csr, err := pemfile.ReadCSR(csrFilename)
if err != nil {
fmt.Fprintln(os.Stderr, err)
os.Exit(1)
}
pubKey, ok := csr.PublicKey.(*rsa.PublicKey)
if !ok {
fmt.Fprintf(os.Stderr, "%s: public key is not RSA\n", csrFilename)
os.Exit(1)
}
// build the certificate template
var (
keyUsage x509.KeyUsage
extKeyUsage []x509.ExtKeyUsage
)
switch {
// TODO: CLI flags
case len(csr.DNSNames) == 0 && len(csr.IPAddresses) == 0:
extKeyUsage = append(extKeyUsage, x509.ExtKeyUsageClientAuth)
default:
extKeyUsage = append(extKeyUsage, x509.ExtKeyUsageServerAuth)
}
template := &x509.Certificate{
KeyUsage: keyUsage,
ExtKeyUsage: extKeyUsage,
Subject: csr.Subject,
NotBefore: from,
NotAfter: until,
DNSNames: csr.DNSNames,
IPAddresses: csr.IPAddresses,
}
// sign the certificate
cert, auditDir, err := ca.Sign(template, pubKey)
if err != nil {
fmt.Fprintln(os.Stderr, err)
os.Exit(1)
}
raw := pem.EncodeToMemory(&pem.Block{
Type: pemfile.TypeX509Certificate,
Bytes: cert.Raw,
})
// copy CSR to audit dir
os.WriteFile(filepath.Join(auditDir, "csr.pem"), pem.EncodeToMemory(&pem.Block{
Type: pemfile.TypeX509CSR,
Bytes: csr.Raw,
}), 0600)
// write cert to output file
switch outputFilename {
case "", "-":
os.Stdout.Write(raw)
default:
if err := os.WriteFile(outputFilename, raw, 0600); err != nil {
fmt.Fprintln(os.Stderr, err)
os.Exit(1)
}
}
}