Files
shhh/internal/clis/hmpki/generate_client_cert.go
2026-10-25 02:18:46 -07:00

105 lines
2.4 KiB
Go

package hmpki
import (
"crypto/rand"
"crypto/x509"
"crypto/x509/pkix"
"encoding/pem"
"path"
"time"
"git.handmadecities.com/HMC/shhh/pkg/pki"
"github.com/spf13/cobra"
)
func init() {
generateCmd.AddCommand(generateClientCertCmd)
generateClientCertCmd.Flags().StringVar(
&CAFile,
"ca",
"",
"File for the CA that will sign the leaf",
)
generateClientCertCmd.MarkFlagRequired("ca")
generateClientCertCmd.MarkFlagFilename("ca")
generateClientCertCmd.Flags().StringVar(
&CAKeyFile,
"ca-key",
"",
"File for the CA private key that will sign the leaf",
)
generateClientCertCmd.MarkFlagRequired("ca-key")
generateClientCertCmd.MarkFlagFilename("ca-key")
generateClientCertCmd.Flags().StringVar(
&CommonName,
"common-name",
"",
"Common Name for the CA",
)
generateClientCertCmd.MarkFlagRequired("common-name")
}
var generateClientCertCmd = &cobra.Command{
Use: "client-cert",
Short: "Generate a leaf client certificate and private key",
RunE: func(cmd *cobra.Command, args []string) error {
ca, err := pki.ParseCertFromFile(CAFile)
if err != nil {
return err
}
caKey, err := pki.ParseKeyFromFile(CAKeyFile)
if err != nil {
return err
}
crtKey := pki.NewKey()
clientCrtTmpl := &x509.Certificate{
SerialNumber: pki.NewCertSerialNumber(),
Subject: pkix.Name{
CommonName: CommonName,
},
// Leaf certs valid for 1 year.
NotBefore: time.Now(),
NotAfter: time.Now().AddDate(1, 0, 0),
// This cert is a leaf, and not a CA.
IsCA: false,
// Disambiguate `IsCA`
BasicConstraintsValid: true,
KeyUsage: x509.KeyUsageDigitalSignature,
ExtKeyUsage: []x509.ExtKeyUsage{x509.ExtKeyUsageClientAuth},
}
clientCrtBytes, err := x509.CreateCertificate(
rand.Reader,
clientCrtTmpl,
// CA is the parent.
ca,
// The cert embeds its own public key.
&crtKey.PublicKey,
// The CA's private key is the one signing the leaf cert.
caKey,
)
clientCrtPEMBytes := pem.EncodeToMemory(&pem.Block{
Type: pki.PEMTypeCertificate,
Bytes: clientCrtBytes,
})
// Write cert to disk.
crtfn := path.Join(OutDir, Name+".crt")
err = createFileWith(crtfn, clientCrtPEMBytes, pki.CertFilePerms)
if err != nil {
return err
}
// Write cert private key to disk.
keyfn := path.Join(OutDir, Name+".key")
err = createFileWith(keyfn, pki.MarshalKeyToPEM(crtKey), pki.PrivateKeyFilePerms)
if err != nil {
return err
}
return nil
},
}