feat: Command to generate a CA.
This commit is contained in:
1 parent
b593b083de
commit
76854f4e4b
5 files changed
+120
-1
No files matched your search
@@ -4,8 +4,12 @@ import (
|
||||
"github.com/spf13/cobra"
|
||||
)
|
||||
|
||||
// Needed by all subcommands.
|
||||
var Output string
|
||||
|
||||
// Needed by some subcommands.
|
||||
var KeyFile string
|
||||
|
||||
func init() {
|
||||
rootCmd.AddCommand(generateCmd)
|
||||
|
||||
|
||||
@@ -0,0 +1,107 @@
|
||||
package hmpki
|
||||
|
||||
import (
|
||||
"crypto/ecdsa"
|
||||
"crypto/rand"
|
||||
"crypto/x509"
|
||||
"crypto/x509/pkix"
|
||||
"encoding/pem"
|
||||
"errors"
|
||||
"math"
|
||||
"math/big"
|
||||
"os"
|
||||
"time"
|
||||
|
||||
"git.handmadecities.com/HMC/shhh/pkg/pki"
|
||||
"github.com/spf13/cobra"
|
||||
)
|
||||
|
||||
func init() {
|
||||
generateCmd.AddCommand(generateCACmd)
|
||||
|
||||
generateCACmd.Flags().StringVar(
|
||||
&KeyFile,
|
||||
"key-file",
|
||||
"",
|
||||
"File that contains the private key that will be associated to the CA",
|
||||
)
|
||||
generateCACmd.MarkFlagRequired("key-file")
|
||||
generateCACmd.MarkFlagFilename("key-file")
|
||||
}
|
||||
|
||||
var generateCACmd = &cobra.Command{
|
||||
Use: "ca",
|
||||
Short: "Generate a Certificate Authority",
|
||||
RunE: func(cmd *cobra.Command, args []string) error {
|
||||
// Read key from KeyFile.
|
||||
keyPemBytes, err := os.ReadFile(KeyFile)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
privBlock, _ := pem.Decode(keyPemBytes)
|
||||
if privBlock == nil || privBlock.Type != pki.PEMTypePrivateKey {
|
||||
return errors.New("Invalid pem key file, or first block is not a private key")
|
||||
}
|
||||
rawKey, err := x509.ParsePKCS8PrivateKey(privBlock.Bytes)
|
||||
|
||||
key, ok := rawKey.(*ecdsa.PrivateKey)
|
||||
if !ok {
|
||||
return errors.New("key file did not contain an ecdsa private key")
|
||||
}
|
||||
|
||||
// Cryptographically random 64bit number as the serial.
|
||||
sn, err := rand.Int(rand.Reader, big.NewInt(math.MaxInt64))
|
||||
if err != nil {
|
||||
errors.New("Could not generate a ca serial number")
|
||||
}
|
||||
caTmpl := &x509.Certificate{
|
||||
SerialNumber: sn,
|
||||
Subject: pkix.Name{
|
||||
// TODO: Accept common name as a flag.
|
||||
CommonName: "Some Common Name",
|
||||
},
|
||||
// Valid starting now and for 10 years.
|
||||
NotBefore: time.Now(),
|
||||
NotAfter: time.Now().AddDate(10, 0, 0),
|
||||
// This cert is a CA.
|
||||
IsCA: true,
|
||||
// No intermeddiate CAs, just one root that can issue leaf certs.
|
||||
MaxPathLen: 0,
|
||||
MaxPathLenZero: true,
|
||||
// Disambiguate `IsCA` and path len settings from their zero value.
|
||||
BasicConstraintsValid: true,
|
||||
// Only allow to sign new certs, and cert revokation lists.
|
||||
// Can't be used as a server or client cert itself.
|
||||
KeyUsage: x509.KeyUsageCertSign | x509.KeyUsageCRLSign,
|
||||
}
|
||||
caBytes, err := x509.CreateCertificate(
|
||||
rand.Reader,
|
||||
// Same template and parent, i.e. self-signed.
|
||||
caTmpl,
|
||||
caTmpl,
|
||||
&key.PublicKey,
|
||||
key,
|
||||
)
|
||||
caPEMBytes := pem.EncodeToMemory(&pem.Block{
|
||||
Type: pki.PEMTypeCertificate,
|
||||
Bytes: caBytes,
|
||||
})
|
||||
|
||||
caf, err := os.OpenFile(
|
||||
Output,
|
||||
// Write only, and fail if it alreay exists.
|
||||
os.O_WRONLY|os.O_CREATE|os.O_EXCL,
|
||||
pki.CertFilePerms,
|
||||
)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
defer caf.Close()
|
||||
if _, err = caf.Write(caPEMBytes); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
// Write ca.crt to Output
|
||||
return nil
|
||||
},
|
||||
}
|
||||
@@ -31,7 +31,7 @@ var generateKeyCmd = &cobra.Command{
|
||||
}
|
||||
|
||||
pemBytes := pem.EncodeToMemory(&pem.Block{
|
||||
Type: "PRIVATE KEY",
|
||||
Type: pki.PEMTypePrivateKey,
|
||||
Bytes: der,
|
||||
})
|
||||
|
||||
|
||||
@@ -2,4 +2,8 @@ package pki
|
||||
|
||||
import "os"
|
||||
|
||||
// RW only by the owner.
|
||||
const PrivateKeyFilePerms os.FileMode = 0600
|
||||
|
||||
// W by owner, R by others.
|
||||
const CertFilePerms os.FileMode = 0644
|
||||
@@ -0,0 +1,4 @@
|
||||
package pki
|
||||
|
||||
const PEMTypePrivateKey = "PRIVATE KEY"
|
||||
const PEMTypeCertificate = "CERTIFICATE"
|
||||
Reference in new issue
Block a user