diff --git a/cmd/keycard/shell.go b/cmd/keycard/shell.go index 5500af3..6e074f7 100644 --- a/cmd/keycard/shell.go +++ b/cmd/keycard/shell.go @@ -59,6 +59,7 @@ func NewShell(t globalplatform.Transmitter) *Shell { "keycard-generate-key": s.commandKeycardGenerateKey, "keycard-derive-key": s.commandKeycardDeriveKey, "keycard-sign": s.commandKeycardSign, + "keycard-set-pinless-path": s.commandKeycardSetPinlessPath, } return s @@ -430,6 +431,20 @@ func (s *Shell) commandKeycardSign(args ...string) error { return nil } +func (s *Shell) commandKeycardSetPinlessPath(args ...string) error { + if err := s.requireArgs(args, 1); err != nil { + return err + } + + logger.Info(fmt.Sprintf("set pinless path %s", args[0])) + if err := s.kCmdSet.SetPinlessPath(args[0]); err != nil { + logger.Error("set pinless path failed", "error", err) + return err + } + + return nil +} + func (s *Shell) requireArgs(args []string, possibleArgsN ...int) error { for _, n := range possibleArgsN { if len(args) == n { diff --git a/command_set.go b/command_set.go index 2f966f4..13934f1 100644 --- a/command_set.go +++ b/command_set.go @@ -196,6 +196,16 @@ func (cs *CommandSet) DeriveKey(path string) error { return cs.checkOK(resp, err) } +func (cs *CommandSet) SetPinlessPath(path string) error { + cmd, err := NewCommandDeriveKey(path) + if err != nil { + return err + } + + resp, err := cs.sc.Send(cmd) + return cs.checkOK(resp, err) +} + func (cs *CommandSet) Sign(data []byte) (*types.Signature, error) { cmd, err := NewCommandSign(data) if err != nil { diff --git a/commands.go b/commands.go index 1949f1d..1ba64b5 100644 --- a/commands.go +++ b/commands.go @@ -20,6 +20,7 @@ const ( InsVerifyPIN = uint8(0x20) InsDeriveKey = uint8(0xD1) InsSign = uint8(0xC0) + InsSetPinlessPath = uint8(0xC1) P1PairingFirstStep = uint8(0x00) P1PairingFinalStep = uint8(0x01) @@ -144,6 +145,32 @@ func NewCommandDeriveKey(pathStr string) (*apdu.Command, error) { ), nil } +func NewCommandSetPinlessPath(pathStr string) (*apdu.Command, error) { + startingPoint, path, err := derivationpath.Decode(pathStr) + if err != nil { + return nil, err + } + + if startingPoint != derivationpath.StartingPointMaster { + return nil, fmt.Errorf("pinless path must be set with an absolute path") + } + + data := new(bytes.Buffer) + for _, segment := range path { + if err := binary.Write(data, binary.BigEndian, segment); err != nil { + return nil, err + } + } + + return apdu.NewCommand( + globalplatform.ClaGp, + InsSetPinlessPath, + uint8(0), + uint8(0), + data.Bytes(), + ), nil +} + func NewCommandSign(data []byte) (*apdu.Command, error) { if len(data) != 32 { return nil, fmt.Errorf("data length must be 32, got %d", len(data))