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