diff --git a/Makefile b/Makefile index 13f0d9d..f2bd606 100644 --- a/Makefile +++ b/Makefile @@ -1,6 +1,6 @@ .PHONY: test test: mod-tidy generate - go test -v ./... + CGO_ENABLED=1 go test -v ./... .PHONY: generate generate: mod-tidy @@ -12,4 +12,4 @@ mod-tidy: .PHONY: build build: test - go build ./cmd/piv-agent + CGO_ENABLED=1 go build ./cmd/piv-agent diff --git a/cmd/piv-agent/setup.go b/cmd/piv-agent/setup.go index b7776ff..d431763 100644 --- a/cmd/piv-agent/setup.go +++ b/cmd/piv-agent/setup.go @@ -21,7 +21,8 @@ type SetupCmd struct { DecryptingKeys []string `kong:"default='cached,always,never',enum='cached,always,never',help='Generate decrypting keys with various touch policies (possible values: cached,always,never)'"` } -func interactivePIN() (uint64, error) { +// interactiveNewPIN prompts twice for a new PIN. +func interactiveNewPIN() (uint64, error) { fmt.Print("Enter a new PIN/PUK (6-8 digits): ") rawPIN, err := terminal.ReadPassword(int(os.Stdin.Fd())) fmt.Println() @@ -49,7 +50,7 @@ func (cmd *SetupCmd) Run() error { // if PIN has not been specified, ask interactively var err error if cmd.PIN == 0 { - cmd.PIN, err = interactivePIN() + cmd.PIN, err = interactiveNewPIN() if err != nil { return err } diff --git a/cmd/piv-agent/setupslots.go b/cmd/piv-agent/setupslots.go index e14a6df..c31648d 100644 --- a/cmd/piv-agent/setupslots.go +++ b/cmd/piv-agent/setupslots.go @@ -3,10 +3,12 @@ package main import ( "errors" "fmt" + "os" "strconv" "github.com/smlx/piv-agent/internal/pinentry" "github.com/smlx/piv-agent/internal/securitykey" + "golang.org/x/crypto/ssh/terminal" ) // SetupSlotsCmd represents the setup command. @@ -14,12 +16,31 @@ type SetupSlotsCmd struct { Card string `kong:"help='Specify a smart card device'"` ResetSlots bool `kong:"help='Overwrite existing keys in the targeted slots'"` PIN uint64 `kong:"help='The PIN/PUK of the device (6-8 digits). Will be prompted interactively if not provided.'"` - SigningKeys []string `kong:"required,enum='cached,always,never',help='Set up slots for signing keys with various touch policies (possible values cached,always,never)'"` - DecryptingKeys []string `kong:"required,enum='cached,always,never',help='Set up slots for a decrypting keys with various touch polcies (possible values cached,always,never)'"` + SigningKeys []string `kong:"enum='cached,always,never',help='Set up slots for signing keys with various touch policies (possible values cached,always,never)'"` + DecryptingKeys []string `kong:"enum='cached,always,never',help='Set up slots for a decrypting keys with various touch polcies (possible values cached,always,never)'"` +} + +// interactivePIN prompts once for an existing PIN. +func interactivePIN() (uint64, error) { + fmt.Print("Enter the PIN/PUK (6-8 digits): ") + rawPIN, err := terminal.ReadPassword(int(os.Stdin.Fd())) + fmt.Println() + if err != nil { + return 0, fmt.Errorf("couldn't read PIN/PUK: %w", err) + } + pin, err := strconv.ParseUint(string(rawPIN), 10, 64) + if err != nil { + return 0, fmt.Errorf("invalid characters: %w", err) + } + return pin, nil } // Run the setup-slot command to configure a slot on a security key. func (cmd *SetupSlotsCmd) Run() error { + // validate keys specified + if len(cmd.SigningKeys) == 0 && len(cmd.DecryptingKeys) == 0 { + return fmt.Errorf("at least one key slot must be specified via --signing-keys=... or --decrypting-keys=... ") + } // if PIN has not been specified, ask interactively var err error if cmd.PIN == 0 {