From 27b7288e07b5c496d39664246775a6aa50db34b5 Mon Sep 17 00:00:00 2001 From: "Greg T. Wallace" Date: Fri, 2 Feb 2024 18:35:22 -0500 Subject: [PATCH] create/install: add support for key pem in args --- pkg/app/cmd_create.go | 14 +++----- pkg/app/cmd_install.go | 13 +++---- pkg/app/config.go | 81 +++++++++++++++++++++++++++++++++++++----- pkg/app/pem_to_p15.go | 16 ++------- 4 files changed, 82 insertions(+), 42 deletions(-) diff --git a/pkg/app/cmd_create.go b/pkg/app/cmd_create.go index e2e60e4..209f10b 100644 --- a/pkg/app/cmd_create.go +++ b/pkg/app/cmd_create.go @@ -2,7 +2,6 @@ package app import ( "context" - "errors" "fmt" "os" ) @@ -17,20 +16,15 @@ func (app *app) cmdCreate(_ context.Context, args []string) error { return fmt.Errorf("create: failed, %w (%d)", ErrExtraArgs, len(args)) } - // key must be specified - if app.config.create.keyPemFilePath == nil || *app.config.create.keyPemFilePath == "" { - return errors.New("create: failed, key not specified") - } - - // cert must be specified - if app.config.create.certPemFilePath == nil || *app.config.create.certPemFilePath == "" { - return errors.New("create: failed, cert not specified") + keyPem, certPem, err := app.config.create.keyCertPemCfg.GetPemBytes("create") + if err != nil { + return err } // validation done // make p15 file - apcFile, err := app.pemToAPCP15(*app.config.create.keyPemFilePath, *app.config.create.certPemFilePath, "create") + apcFile, err := app.pemToAPCP15(keyPem, certPem, "create") if err != nil { return err } diff --git a/pkg/app/cmd_install.go b/pkg/app/cmd_install.go index 04978b4..8162e5b 100644 --- a/pkg/app/cmd_install.go +++ b/pkg/app/cmd_install.go @@ -36,14 +36,9 @@ func (app *app) cmdInstall(cmdCtx context.Context, args []string) error { return errors.New("install: failed, fingerprint not specified") } - // key must be specified - if app.config.install.keyPemFilePath == nil || *app.config.install.keyPemFilePath == "" { - return errors.New("install: failed, key not specified") - } - - // cert must be specified - if app.config.install.certPemFilePath == nil || *app.config.install.certPemFilePath == "" { - return errors.New("install: failed, cert not specified") + keyPem, certPem, err := app.config.install.keyCertPemCfg.GetPemBytes("install") + if err != nil { + return err } // host to install on must be specified @@ -54,7 +49,7 @@ func (app *app) cmdInstall(cmdCtx context.Context, args []string) error { // validation done // make p15 file - apcFile, err := app.pemToAPCP15(*app.config.install.keyPemFilePath, *app.config.install.certPemFilePath, "install") + apcFile, err := app.pemToAPCP15(keyPem, certPem, "install") if err != nil { return err } diff --git a/pkg/app/config.go b/pkg/app/config.go index 40feb41..c2980b8 100644 --- a/pkg/app/config.go +++ b/pkg/app/config.go @@ -2,6 +2,8 @@ package app import ( "errors" + "fmt" + "os" "github.com/peterbourgon/ff/v4" ) @@ -10,21 +12,28 @@ var ( ErrExtraArgs = errors.New("extra args present") ) +// 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 { logLevel *string create struct { - keyPemFilePath *string - certPemFilePath *string - outFilePath *string + keyCertPemCfg + outFilePath *string } install struct { - keyPemFilePath *string - certPemFilePath *string - hostAndPort *string - fingerprint *string - username *string - password *string + keyCertPemCfg + hostAndPort *string + fingerprint *string + username *string + password *string } } @@ -57,6 +66,8 @@ func (app *app) getConfig(args []string) error { cfg.create.keyPemFilePath = createFlags.StringLong("keyfile", "", "path and filename of the 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-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 p15 file to") createCmd := &ff.Command{ @@ -74,6 +85,8 @@ func (app *app) getConfig(args []string) error { cfg.install.keyPemFilePath = installFlags.StringLong("keyfile", "", "path and filename of the 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-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") @@ -99,3 +112,53 @@ func (app *app) getConfig(args []string) error { 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 +} diff --git a/pkg/app/pem_to_p15.go b/pkg/app/pem_to_p15.go index 17297a1..cab6885 100644 --- a/pkg/app/pem_to_p15.go +++ b/pkg/app/pem_to_p15.go @@ -3,23 +3,11 @@ package app import ( "apc-p15-tool/pkg/pkcs15" "fmt" - "os" ) // pemToAPCP15 reads the specified pem files and returns the apc p15 bytes -func (app *app) pemToAPCP15(keyFileName, certFileName, parentCmdName string) ([]byte, error) { - app.logger.Infof("%s: making apc p15 file from pem files", parentCmdName) - - // Read in PEM files - keyPem, err := os.ReadFile(keyFileName) - if err != nil { - return nil, fmt.Errorf("%s: failed to read key file (%w)", parentCmdName, err) - } - - certPem, err := os.ReadFile(certFileName) - if err != nil { - return nil, fmt.Errorf("%s: failed to read cert file (%w)", parentCmdName, err) - } +func (app *app) pemToAPCP15(keyPem, certPem []byte, parentCmdName string) ([]byte, error) { + app.logger.Infof("%s: making apc p15 file from pem", parentCmdName) // make p15 struct p15, err := pkcs15.ParsePEMToPKCS15(keyPem, certPem)