Skip to content

Commit

Permalink
TBD: command to rotate device CAs
Browse files Browse the repository at this point in the history
Signed-off-by: Volodymyr Khoroz <[email protected]>
  • Loading branch information
vkhoroz committed Aug 19, 2024
1 parent b4842c4 commit 80f29d6
Show file tree
Hide file tree
Showing 3 changed files with 79 additions and 0 deletions.
66 changes: 66 additions & 0 deletions subcommands/keys/ca_renewal_resign_device_ca.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,66 @@
package keys

import (
"fmt"
"os"

"github.com/spf13/cobra"
"github.com/spf13/viper"

//"github.com/foundriesio/fioctl/client"
"github.com/foundriesio/fioctl/subcommands"
"github.com/foundriesio/fioctl/x509"
)

func init() {
cmd := &cobra.Command{
Use: "re-sign-device-ca <PKI Directory> [<Old PKI Directory>]",
Short: "Re-sign all existing Device CAs with a new root CA for your Factory PKI",
Run: doReSignDeviceCaRenewal,
Args: cobra.RangeArgs(1, 2),
Long: `Re-sign all existing Device CAs with a new root CA for your Factory PKI.
Both currently active and disabled Device CAs are being re-signed.
All their properties are preserved, including a serial number.
Only the signature and authority key ID are being changed.
This allows old certificates (issued by a previous root CA) to continue being used to issue device client certificates.
Re-signed device CA certificates are stored in the provided PKI directory.
An old PKI directory is used to locate corresponding private keys, and copy them into the PKI directory.
Each located device CA gets the same file name, as it was in the old PKI directory.
If a device CA certificate cannot be located in an old PKI directory - it does not get stored locally.
If an old PKI directory argument is not provided, new certificates are not stored locally.
`,
}
caRenewalCmd.AddCommand(cmd)
cmd.Flags().StringVarP(&hsmModule, "hsm-module", "", "", "Load a root CA key from a PKCS#11 compatible HSM using this module")
cmd.Flags().StringVarP(&hsmPin, "hsm-pin", "", "", "The PKCS#11 PIN to log into the HSM")
cmd.Flags().StringVarP(&hsmTokenLabel, "hsm-token-label", "", "", "The label of the HSM token holding the root CA key")
}

func doReSignDeviceCaRenewal(cmd *cobra.Command, args []string) {
factory := viper.GetString("factory")
certsDir := args[0]
oldCertsDir := args[1]
subcommands.DieNotNil(os.Chdir(certsDir))
hsm, err := x509.ValidateHsmArgs(
hsmModule, hsmPin, hsmTokenLabel, "--hsm-module", "--hsm-pin", "--hsm-token-label")
subcommands.DieNotNil(err)
x509.InitHsm(hsm)

// TBD: load serial-to-filename map from oldCertsDir
// TBD: fetch current device CAs from the server, re-sign them, store locally (if matched), and upload back.
// TBD - linter
fmt.Println(factory, oldCertsDir)
}

// TBD: commands to add:
// # Re-sign existing TLS certs. As we don't care for their serial numbers - it is an alias to "fioctl keys rotate-tls".
// - fioctl keys renewal re-sign-tls <PKI Directory>
// # Revoke a specific root CA by its serial number. Cannot revoke currently active root CA.
// # This also revokes the cross-signed renewal bundle root CAs, associated with this root CA.
// - fioctl keys renewal revoke-root <PKI Directory> --serial

// There will be no such command as `fioctl keys renewal finish`.
// Otherwise, users would often abuse it, leading to devices losing connectivity.
// Having harder to grasp command names, like e.g. revoke-root makes this process more controlled.
5 changes: 5 additions & 0 deletions x509/bash.go
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@ package x509

import (
"crypto"
"crypto/x509"
"os"
"os/exec"

Expand Down Expand Up @@ -164,6 +165,10 @@ func SignEl2GoCsr(csrPem string) string {
return signCaCsr("el2g-*", csrPem)
}

func ReSignCrt(crt *x509.Certificate) string {
return neverland()
}

func CreateCrl(serials map[string]int) string {
return neverland()
}
Expand Down
8 changes: 8 additions & 0 deletions x509/golang.go
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,7 @@ func CreateFactoryCrossCa(ou string, pubkey crypto.PublicKey) string {
// This function does an inverse: produces a factory CA with a public key "borrowed" from another factory CA.
// The end result is the same, but we don't need to export the internal key storage interface.
// This certificate is not written to disk, as it is only needed intermittently.
// Cannot use a ReSignCrt as we need a new certificate here (with e.g. a new serial number).
priv := factoryCaKeyStorage.loadKey()
crtTemplate := genFactoryCaTemplate(marshalSubject(factoryCaName, ou))
return genCertificate(crtTemplate, crtTemplate, pubkey, priv)
Expand Down Expand Up @@ -74,6 +75,13 @@ func SignEstCsr(csrPem string) string {
return genTlsCert(csr.Subject, csr.DNSNames, csr.PublicKey)
}

func ReSignCrt(crt *x509.Certificate) string {
// Use an input certificate as a template for a new certificate, preserving all its properties except a signature.
factoryKey := factoryCaKeyStorage.loadKey()
factoryCa := LoadCertFromFile(FactoryCaCertFile)
return genCertificate(crt, factoryCa, crt.PublicKey, factoryKey)
}

var oidExtensionReasonCode = []int{2, 5, 29, 21}

func CreateCrl(serials map[string]int) string {
Expand Down

0 comments on commit 80f29d6

Please sign in to comment.