mirror of
https://github.com/gregtwallace/apc-p15-tool.git
synced 2025-01-22 08:14:08 +00:00
01be6ca577
The NMC Security Wizard can also produce .p15 files that contain just a private key. Add this ability to this tool. When the `create` function is used, both files will be outputted.
171 lines
6.1 KiB
Go
171 lines
6.1 KiB
Go
package app
|
|
|
|
import (
|
|
"errors"
|
|
"fmt"
|
|
"os"
|
|
|
|
"github.com/peterbourgon/ff/v4"
|
|
)
|
|
|
|
var (
|
|
ErrExtraArgs = errors.New("extra args present")
|
|
|
|
environmentVarPrefix = "APC_P15_TOOL"
|
|
)
|
|
|
|
// keyCertPemCfg contains values common to subcommands that need to use key
|
|
// and cert pem
|
|
type keyCertPemCfg struct {
|
|
keyPemFilePath *string
|
|
certPemFilePath *string
|
|
keyPem *string
|
|
certPem *string
|
|
}
|
|
|
|
// app's config options from user
|
|
type config struct {
|
|
debugLogging *bool
|
|
create struct {
|
|
keyCertPemCfg
|
|
outFilePath *string
|
|
outKeyFilePath *string
|
|
}
|
|
install struct {
|
|
keyCertPemCfg
|
|
hostAndPort *string
|
|
fingerprint *string
|
|
username *string
|
|
password *string
|
|
restartWebUI *bool
|
|
insecureCipher *bool
|
|
}
|
|
}
|
|
|
|
// getConfig returns the app's configuration from either command line args,
|
|
// or environment variables
|
|
func (app *app) getConfig(args []string) error {
|
|
// make config
|
|
cfg := &config{}
|
|
|
|
// commands:
|
|
// create
|
|
// install
|
|
// TODO:
|
|
// unpack (both key & key+cert)
|
|
|
|
// apc-p15-tool -- root command
|
|
rootFlags := ff.NewFlagSet("apc-p15-tool")
|
|
|
|
cfg.debugLogging = rootFlags.BoolLong("debug", "set this flag to enable additional debug logging messages")
|
|
|
|
rootCmd := &ff.Command{
|
|
Name: "apc-p15-tool",
|
|
Usage: "apc-p15-tool [FLAGS] SUBCOMMAND ...",
|
|
Flags: rootFlags,
|
|
}
|
|
|
|
// create -- subcommand
|
|
createFlags := ff.NewFlagSet("create").SetParent(rootFlags)
|
|
|
|
cfg.create.keyPemFilePath = createFlags.StringLong("keyfile", "", "path and filename of the rsa-1024 or rsa-2048 key in pem format")
|
|
cfg.create.certPemFilePath = createFlags.StringLong("certfile", "", "path and filename of the certificate in pem format")
|
|
cfg.create.keyPem = createFlags.StringLong("keypem", "", "string of the rsa-1024 or rsa-2048 key in pem format")
|
|
cfg.create.certPem = createFlags.StringLong("certpem", "", "string of the certificate in pem format")
|
|
cfg.create.outFilePath = createFlags.StringLong("outfile", createDefaultOutFilePath, "path and filename to write the key+cert p15 file to")
|
|
cfg.create.outKeyFilePath = createFlags.StringLong("outkeyfile", createDefaultOutKeyFilePath, "path and filename to write the key p15 file to")
|
|
|
|
createCmd := &ff.Command{
|
|
Name: "create",
|
|
Usage: "apc-p15-tool create --keyfile key.pem --certfile cert.pem [--outfile apctool.p15]",
|
|
ShortHelp: "create an apc p15 file from the specified key and cert pem files",
|
|
Flags: createFlags,
|
|
Exec: app.cmdCreate,
|
|
}
|
|
|
|
rootCmd.Subcommands = append(rootCmd.Subcommands, createCmd)
|
|
|
|
// install -- subcommand
|
|
installFlags := ff.NewFlagSet("install").SetParent(rootFlags)
|
|
|
|
cfg.install.keyPemFilePath = installFlags.StringLong("keyfile", "", "path and filename of the rsa-1024 or rsa-2048 key in pem format")
|
|
cfg.install.certPemFilePath = installFlags.StringLong("certfile", "", "path and filename of the certificate in pem format")
|
|
cfg.install.keyPem = installFlags.StringLong("keypem", "", "string of the rsa-1024 or rsa-2048 key in pem format")
|
|
cfg.install.certPem = installFlags.StringLong("certpem", "", "string of the certificate in pem format")
|
|
cfg.install.hostAndPort = installFlags.StringLong("apchost", "", "hostname:port of the apc ups to install the certificate on")
|
|
cfg.install.fingerprint = installFlags.StringLong("fingerprint", "", "the SHA256 fingerprint value of the ups' ssh server")
|
|
cfg.install.username = installFlags.StringLong("username", "", "username to login to the apc ups")
|
|
cfg.install.password = installFlags.StringLong("password", "", "password to login to the apc ups")
|
|
cfg.install.restartWebUI = installFlags.BoolLong("restartwebui", "some devices may need a webui restart to begin using the new cert, enabling this option sends the restart command after the p15 is installed")
|
|
cfg.install.insecureCipher = installFlags.BoolLong("insecurecipher", "allows the use of insecure ssh ciphers (NOT recommended)")
|
|
|
|
installCmd := &ff.Command{
|
|
Name: "install",
|
|
Usage: "apc-p15-tool install --keyfile key.pem --certfile cert.pem --apchost example.com:22 --fingerprint 123abc --username apc --password test",
|
|
ShortHelp: "install the specified key and cert pem files on an apc ups (they will be converted to a comaptible p15 file)",
|
|
Flags: installFlags,
|
|
Exec: app.cmdInstall,
|
|
}
|
|
|
|
rootCmd.Subcommands = append(rootCmd.Subcommands, installCmd)
|
|
|
|
// set cfg & parse
|
|
app.config = cfg
|
|
app.cmd = rootCmd
|
|
err := app.cmd.Parse(args[1:], ff.WithEnvVarPrefix(environmentVarPrefix))
|
|
if err != nil {
|
|
return err
|
|
}
|
|
|
|
return nil
|
|
}
|
|
|
|
// GetPemBytes returns the key and cert pem bytes as specified in keyCertPemCfg
|
|
// or an error if it cant get the bytes of both
|
|
func (kcCfg *keyCertPemCfg) GetPemBytes(subcommand string) (keyPem, certPem []byte, err error) {
|
|
// key pem (from arg or file)
|
|
if kcCfg.keyPem != nil && *kcCfg.keyPem != "" {
|
|
// error if filename is also set
|
|
if kcCfg.keyPemFilePath != nil && *kcCfg.keyPemFilePath != "" {
|
|
return nil, nil, fmt.Errorf("%s: failed, both key pem and key file specified", subcommand)
|
|
}
|
|
|
|
// use pem
|
|
keyPem = []byte(*kcCfg.keyPem)
|
|
} else {
|
|
// pem wasn't specified, try reading file
|
|
if kcCfg.keyPemFilePath == nil || *kcCfg.keyPemFilePath == "" {
|
|
return nil, nil, fmt.Errorf("%s: failed, neither key pem nor key file specified", subcommand)
|
|
}
|
|
|
|
// read file to get pem
|
|
keyPem, err = os.ReadFile(*kcCfg.keyPemFilePath)
|
|
if err != nil {
|
|
return nil, nil, fmt.Errorf("%s: failed to read key file (%w)", subcommand, err)
|
|
}
|
|
}
|
|
|
|
// cert pem (repeat same process)
|
|
if kcCfg.certPem != nil && *kcCfg.certPem != "" {
|
|
// error if filename is also set
|
|
if kcCfg.certPemFilePath != nil && *kcCfg.certPemFilePath != "" {
|
|
return nil, nil, fmt.Errorf("%s: failed, both cert pem and cert file specified", subcommand)
|
|
}
|
|
|
|
// use pem
|
|
certPem = []byte(*kcCfg.certPem)
|
|
} else {
|
|
// pem wasn't specified, try reading file
|
|
if kcCfg.certPemFilePath == nil || *kcCfg.certPemFilePath == "" {
|
|
return nil, nil, fmt.Errorf("%s: failed, neither cert pem nor cert file specified", subcommand)
|
|
}
|
|
|
|
// read file to get pem
|
|
certPem, err = os.ReadFile(*kcCfg.certPemFilePath)
|
|
if err != nil {
|
|
return nil, nil, fmt.Errorf("%s: failed to read cert file (%w)", subcommand, err)
|
|
}
|
|
}
|
|
|
|
return keyPem, certPem, nil
|
|
}
|