Ledger: implement authorized-path APDU

This commit is contained in:
Vincent Bernardoff 2018-09-27 17:52:05 +08:00 committed by Benjamin Canou
parent 92715a005b
commit 4bb28cd285
No known key found for this signature in database
GPG Key ID: 73607948459DC5F8
4 changed files with 94 additions and 1 deletions

View File

@ -43,8 +43,47 @@ let description =
all connected devices." all connected devices."
let hard = Int32.logor 0x8000_0000l let hard = Int32.logor 0x8000_0000l
let unhard = Int32.logand 0x7fff_ffffl
let is_hard n = Int32.logand 0x8000_0000l n <> 0l
let tezos_root = [hard 44l ; hard 1729l] let tezos_root = [hard 44l ; hard 1729l]
module Bip32_path = struct
let node_of_string str =
match Int32.of_string_opt str with
| Some node -> Some node
| None ->
match Int32.of_string_opt String.(sub str 0 ((length str) - 1)) with
| None -> None
| Some node -> Some (hard node)
let node_of_string_exn str =
match node_of_string str with
| None ->
invalid_arg (Printf.sprintf "node_of_string_exn: got %S" str)
| Some str -> str
let pp_node ppf node =
match is_hard node with
| true -> Fmt.pf ppf "%ld'" (unhard node)
| false -> Fmt.pf ppf "%ld" node
let string_of_node = Fmt.to_to_string pp_node
let path_of_string_exn s =
match String.split_on_char '/' s with
| [""] -> []
| nodes ->
List.map node_of_string_exn nodes
let path_of_string s =
try Some (path_of_string_exn s) with _ -> None
let pp_path =
Fmt.(list ~sep:(const char '/') pp_node)
let string_of_path = Fmt.to_to_string pp_path
end
(* Those are always valid on Ledger Nano S with latest firmware. *) (* Those are always valid on Ledger Nano S with latest firmware. *)
let vendor_id = 0x2c97 let vendor_id = 0x2c97
let product_id = 0x0001 let product_id = 0x0001
@ -454,6 +493,30 @@ let commands =
return_unit return_unit
) ; ) ;
Clic.command ~group
~desc: "Query the path of the authorized key"
no_options
(prefixes [ "get" ; "ledger" ; "authorized" ; "path" ; "for" ]
@@ Public_key.alias_param
@@ stop)
(fun () (name, (pk_uri, _)) (cctxt : Client_context.io_wallet) ->
pkh_of_pk_uri pk_uri >>=? fun root_pkh ->
with_ledger root_pkh begin fun h _version _of_curve _to_curve ->
wrap_ledger_cmd begin fun pp ->
Ledgerwallet_tezos.get_authorized_key ~pp h
end >>=? function
| [] ->
cctxt#message
"@[<v 0>No baking key authorized for %s@]" name
>>= fun () ->
return_unit
| path ->
cctxt#message
"@[<v 0>Authorized baking path: %a@]"
Bip32_path.pp_path path >>= fun () ->
return_unit
end) ;
Clic.command ~group Clic.command ~group
~desc: "Authorize a Ledger to bake for a key" ~desc: "Authorize a Ledger to bake for a key"
no_options no_options

View File

@ -23,6 +23,18 @@
(* *) (* *)
(*****************************************************************************) (*****************************************************************************)
module Bip32_path : sig
val node_of_string : string -> int32 option
val node_of_string_exn : string -> int32
val pp_node : int32 Fmt.t
val string_of_node : int32 -> string
val path_of_string : string -> int32 list option
val path_of_string_exn : string -> int32 list
val pp_path : int32 list Fmt.t
val string_of_path : int32 list -> string
end
include Client_keys.SIGNER include Client_keys.SIGNER
val commands : unit -> Client_context.io_wallet Clic.command list val commands : unit -> Client_context.io_wallet Clic.command list

View File

@ -63,6 +63,7 @@ type ins =
| Sign_unsafe | Sign_unsafe
| Reset_high_watermark | Reset_high_watermark
| Query_high_watermark | Query_high_watermark
| Get_authorized_key
let int_of_ins = function let int_of_ins = function
| Version -> 0x00 | Version -> 0x00
@ -74,6 +75,7 @@ let int_of_ins = function
| Reset_high_watermark -> 0x06 | Reset_high_watermark -> 0x06
| Query_high_watermark -> 0x08 | Query_high_watermark -> 0x08
| Git_commit -> 0x09 | Git_commit -> 0x09
| Get_authorized_key -> 0x07
type curve = type curve =
| Ed25519 | Ed25519
@ -98,6 +100,16 @@ let get_git_commit ?pp ?buf h =
Transport.apdu ~msg:"get_git_commit" ?pp ?buf h apdu >>| Transport.apdu ~msg:"get_git_commit" ?pp ?buf h apdu >>|
Cstruct.to_string Cstruct.to_string
let get_authorized_key ?pp ?buf h =
let apdu = Apdu.create (wrap_ins Get_authorized_key) in
Transport.apdu ~msg:"get_authorized_key" ?pp ?buf h apdu >>| fun path ->
let rec read_numbers acc path =
if Cstruct.len path = 0 then List.rev acc
else
read_numbers (Cstruct.BE.get_uint32 path 0 :: acc)
(Cstruct.shift path 4) in
read_numbers [] (Cstruct.shift path 1)
let write_path cs path = let write_path cs path =
ListLabels.fold_left path ~init:cs ~f:begin fun cs i -> ListLabels.fold_left path ~init:cs ~f:begin fun cs i ->
Cstruct.BE.set_uint32 cs 0 i ; Cstruct.BE.set_uint32 cs 0 i ;

View File

@ -36,7 +36,13 @@ val get_git_commit :
?pp:Format.formatter -> ?buf:Cstruct.t -> ?pp:Format.formatter -> ?buf:Cstruct.t ->
Hidapi.t -> (string, Transport.error) result Hidapi.t -> (string, Transport.error) result
(** [get_git_commit ?pp ?buf ledger] is the git commit information of (** [get_git_commit ?pp ?buf ledger] is the git commit information of
the Ledger app running at [ledger]. *) the Ledger app running at [ledger]. *)
val get_authorized_key :
?pp:Format.formatter -> ?buf:Cstruct.t ->
Hidapi.t -> (int32 list, Transport.error) result
(** [get_authorized_key ?pp ?buf ledger] is the BIP32 path of the key
authorized to bake on the Ledger app running at [ledger]. *)
val get_public_key : val get_public_key :
?prompt:bool -> ?prompt:bool ->