From f69d4a5186eb4164ba99aa70b1137fdaa1f8ebdc Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Gr=C3=A9goire=20Henry?= Date: Sat, 26 May 2018 13:22:47 +0200 Subject: [PATCH] Client: simplify `Client_keys.SIGNER` We now use `Uri.t` to represent public and secret keys. The 'remote' scheme is replaced by `https://`, `unix:///` and `tcp://`. --- src/bin_client/tezos-init-sandboxed-client.sh | 24 +- src/bin_signer/handler.ml | 2 +- src/bin_signer/main_signer.ml | 4 +- src/lib_client_base/client_keys.ml | 328 ++++++------------ src/lib_client_base/client_keys.mli | 108 ++---- src/lib_client_base_unix/client_main_run.ml | 10 +- .../client_keys_commands.ml | 188 ++++++---- src/lib_client_commands/jbuild | 3 +- src/lib_signer_backends/encrypted.ml | 314 ++++++++--------- src/lib_signer_backends/encrypted.mli | 14 +- src/lib_signer_backends/https.ml | 49 +++ .../{remote.mli => https.mli} | 2 +- src/lib_signer_backends/jbuild | 3 +- src/lib_signer_backends/remote.ml | 172 --------- src/lib_signer_backends/socket.ml | 105 ++++++ src/lib_signer_backends/socket.mli | 11 + src/lib_signer_backends/unencrypted.ml | 53 ++- src/lib_signer_backends/unencrypted.mli | 3 + .../lib_baking/client_baking_endorsement.ml | 2 +- .../lib_baking/client_baking_forge.ml | 3 +- .../lib_baking/test/proto_alpha_helpers.ml | 22 +- .../lib_baking/test/proto_alpha_helpers.mli | 2 +- .../lib_client/client_proto_context.ml | 16 +- .../lib_client/client_proto_programs.ml | 2 +- src/proto_alpha/lib_client/jbuild | 1 + .../lib_client/client_proto_main.ml | 2 +- 26 files changed, 662 insertions(+), 781 deletions(-) create mode 100644 src/lib_signer_backends/https.ml rename src/lib_signer_backends/{remote.mli => https.mli} (90%) delete mode 100644 src/lib_signer_backends/remote.ml create mode 100644 src/lib_signer_backends/socket.ml create mode 100644 src/lib_signer_backends/socket.mli diff --git a/src/bin_client/tezos-init-sandboxed-client.sh b/src/bin_client/tezos-init-sandboxed-client.sh index 4de639b46..dd0d900f4 100755 --- a/src/bin_client/tezos-init-sandboxed-client.sh +++ b/src/bin_client/tezos-init-sandboxed-client.sh @@ -190,35 +190,35 @@ log_endorser() { BOOTSTRAP1_IDENTITY="tz1KqTpEZ7Yob7QbPE4Hy4Wo8fHG8LhKxZSx" BOOTSTRAP1_PUBLIC="edpkuBknW28nW72KG6RoHtYW7p12T6GKc7nAbwYX5m8Wd9sDVC9yav" -BOOTSTRAP1_SECRET="edsk3gUfUPyBSfrS9CCgmCiQsTCHGkviBDusMxDJstFtojtc1zcpsh" +BOOTSTRAP1_SECRET="unencrypted:edsk3gUfUPyBSfrS9CCgmCiQsTCHGkviBDusMxDJstFtojtc1zcpsh" BOOTSTRAP2_IDENTITY="tz1gjaF81ZRRvdzjobyfVNsAeSC6PScjfQwN" BOOTSTRAP2_PUBLIC="edpktzNbDAUjUk697W7gYg2CRuBQjyPxbEg8dLccYYwKSKvkPvjtV9" -BOOTSTRAP2_SECRET="edsk39qAm1fiMjgmPkw1EgQYkMzkJezLNewd7PLNHTkr6w9XA2zdfo" +BOOTSTRAP2_SECRET="unencrypted:edsk39qAm1fiMjgmPkw1EgQYkMzkJezLNewd7PLNHTkr6w9XA2zdfo" BOOTSTRAP3_IDENTITY="tz1faswCTDciRzE4oJ9jn2Vm2dvjeyA9fUzU" BOOTSTRAP3_PUBLIC="edpkuTXkJDGcFd5nh6VvMz8phXxU3Bi7h6hqgywNFi1vZTfQNnS1RV" -BOOTSTRAP3_SECRET="edsk4ArLQgBTLWG5FJmnGnT689VKoqhXwmDPBuGx3z4cvwU9MmrPZZ" +BOOTSTRAP3_SECRET="unencrypted:edsk4ArLQgBTLWG5FJmnGnT689VKoqhXwmDPBuGx3z4cvwU9MmrPZZ" BOOTSTRAP4_IDENTITY="tz1b7tUupMgCNw2cCLpKTkSD1NZzB5TkP2sv" BOOTSTRAP4_PUBLIC="edpkuFrRoDSEbJYgxRtLx2ps82UdaYc1WwfS9sE11yhauZt5DgCHbU" -BOOTSTRAP4_SECRET="edsk2uqQB9AY4FvioK2YMdfmyMrer5R8mGFyuaLLFfSRo8EoyNdht3" +BOOTSTRAP4_SECRET="unencrypted:edsk2uqQB9AY4FvioK2YMdfmyMrer5R8mGFyuaLLFfSRo8EoyNdht3" BOOTSTRAP5_IDENTITY="tz1ddb9NMYHZi5UzPdzTZMYQQZoMub195zgv" BOOTSTRAP5_PUBLIC="edpkv8EUUH68jmo3f7Um5PezmfGrRF24gnfLpH3sVNwJnV5bVCxL2n" -BOOTSTRAP5_SECRET="edsk4QLrcijEffxV31gGdN2HU7UpyJjA8drFoNcmnB28n89YjPNRFm" +BOOTSTRAP5_SECRET="unencrypted:edsk4QLrcijEffxV31gGdN2HU7UpyJjA8drFoNcmnB28n89YjPNRFm" -DICTATOR_SECRET="edsk31vznjHSSpGExDMHYASz45VZqXN4DPxvsa4hAyY8dHM28cZzp6" +DICTATOR_SECRET="unencrypted:edsk31vznjHSSpGExDMHYASz45VZqXN4DPxvsa4hAyY8dHM28cZzp6" add_sandboxed_bootstrap_identities() { - ${client} import unencrypted secret key bootstrap1 ${BOOTSTRAP1_SECRET} - ${client} import unencrypted secret key bootstrap2 ${BOOTSTRAP2_SECRET} - ${client} import unencrypted secret key bootstrap3 ${BOOTSTRAP3_SECRET} - ${client} import unencrypted secret key bootstrap4 ${BOOTSTRAP4_SECRET} - ${client} import unencrypted secret key bootstrap5 ${BOOTSTRAP5_SECRET} + ${client} import secret key bootstrap1 ${BOOTSTRAP1_SECRET} + ${client} import secret key bootstrap2 ${BOOTSTRAP2_SECRET} + ${client} import secret key bootstrap3 ${BOOTSTRAP3_SECRET} + ${client} import secret key bootstrap4 ${BOOTSTRAP4_SECRET} + ${client} import secret key bootstrap5 ${BOOTSTRAP5_SECRET} - ${client} import unencrypted secret key dictator ${DICTATOR_SECRET} + ${client} import secret key dictator ${DICTATOR_SECRET} } diff --git a/src/bin_signer/handler.ml b/src/bin_signer/handler.ml index 3bac85ff1..c539c9102 100644 --- a/src/bin_signer/handler.ml +++ b/src/bin_signer/handler.ml @@ -16,7 +16,7 @@ let sign (cctxt : #Client_context.wallet) pkh data = (MBytes.get_uint8 data 0) >>= fun () -> Client_keys.get_key cctxt pkh >>=? fun (name, _pkh, sk_uri) -> log "Signing data for key %s" name >>= fun () -> - Client_keys.sign cctxt sk_uri data >>=? fun signature -> + Client_keys.sign sk_uri data >>=? fun signature -> return signature let public_key (cctxt : #Client_context.wallet) pkh = diff --git a/src/bin_signer/main_signer.ml b/src/bin_signer/main_signer.ml index f61578260..c3027a1b7 100644 --- a/src/bin_signer/main_signer.ml +++ b/src/bin_signer/main_signer.ml @@ -163,7 +163,9 @@ let main () = inherit Client_context_unix.unix_wallet ~base_dir end in Client_keys.register_signer - (module Tezos_signer_backends.Encrypted) ; + (module Tezos_signer_backends.Encrypted.Make(struct + let cctxt = new Client_context_unix.unix_prompter + end)) ; Client_keys.register_signer (module Tezos_signer_backends.Unencrypted) ; let commands = diff --git a/src/lib_client_base/client_keys.ml b/src/lib_client_base/client_keys.ml index 5f2412e96..766d8f701 100644 --- a/src/lib_client_base/client_keys.ml +++ b/src/lib_client_base/client_keys.ml @@ -30,136 +30,63 @@ module Public_key_hash = Client_aliases.Alias (struct let name = "public key hash" end) -type location = string list - -module type LOCATOR = sig - val name : string - type t - - val create : scheme:string -> location:location -> t - val scheme : t -> string - val location : t -> location - val to_string : t -> string - val pp : Format.formatter -> t -> unit -end - -type sk_uri = Sk_locator of { scheme : string ; location : location } -type pk_uri = Pk_locator of { scheme : string ; location : location } - -module Sk_locator = struct - let name = "secret key" - type t = sk_uri - - let create ~scheme ~location = - Sk_locator { scheme ; location } - - let scheme (Sk_locator { scheme }) = scheme - let location (Sk_locator { location }) = location - - let to_string (Sk_locator { scheme ; location }) = - String.concat "/" ((scheme ^ ":") :: List.map Uri.pct_encode location) - - let pp ppf loc = - Format.pp_print_string ppf (to_string loc) -end - -module Pk_locator = struct - let name = "public key" - type t = pk_uri - - let create ~scheme ~location = - Pk_locator { scheme ; location } - - let scheme (Pk_locator { scheme }) = scheme - let location (Pk_locator { location }) = location - - let to_string (Pk_locator { scheme ; location }) = - String.concat "/" ((scheme ^ ":") :: List.map Uri.pct_encode location) - - let pp ppf loc = - Format.pp_print_string ppf (to_string loc) -end - module type KEY = sig type t val to_b58check : t -> string val of_b58check_exn : string -> t end -module Locator (K : KEY) (L : LOCATOR) = struct - include L +let uri_encoding = + Data_encoding.(conv Uri.to_string Uri.of_string string) - let of_unencrypted k = - L.create ~scheme:"unencrypted" - ~location:[K.to_b58check k] - - let of_string s = - match String.index s ':' with - | exception Not_found -> - of_unencrypted (K.of_b58check_exn s) - | i -> - let len = String.length s in - let scheme = String.sub s 0 i in - let location = - String.sub s (i+1) (len-i-1) |> - String.split '/' |> - List.map Uri.pct_decode |> - List.filter ((<>) "") in - create ~scheme ~location - - let of_source s = return (of_string s) - let to_source t = return (to_string t) - - let encoding = Data_encoding.(conv to_string of_string string) +module Entity (Name : sig val name: string end) = struct + include Name + type t = Uri.t + let pp = Uri.pp_hum + let of_source s = return (Uri.of_string s) + let to_source t = return (Uri.to_string t) + let encoding = uri_encoding end -module Secret_key_locator = Locator(Signature.Secret_key)(Sk_locator) -module Secret_key = Client_aliases.Alias (Secret_key_locator) -module Public_key_locator = Locator(Signature.Public_key)(Pk_locator) -module Public_key = Client_aliases.Alias (Public_key_locator) +type pk_uri = Uri.t +let make_pk_uri x = x + +type sk_uri = Uri.t +let make_sk_uri x = x + +module Secret_key = + Client_aliases.Alias (Entity(struct let name = "secret_key" end)) +module Public_key = + Client_aliases.Alias (Entity(struct let name = "public_key" end)) module type SIGNER = sig - type secret_key - type public_key val scheme : string val title : string val description : string - val init : #Client_context.io_wallet -> unit tzresult Lwt.t - val sk_locator_of_human_input : #Client_context.io_wallet -> string list -> sk_uri tzresult Lwt.t - val pk_locator_of_human_input : #Client_context.io_wallet -> string list -> pk_uri tzresult Lwt.t - val sk_of_locator : sk_uri -> secret_key tzresult Lwt.t - val pk_of_locator : pk_uri -> public_key tzresult Lwt.t - val sk_to_locator : secret_key -> sk_uri Lwt.t - val pk_to_locator : public_key -> pk_uri Lwt.t - val neuterize : secret_key -> public_key Lwt.t - val public_key : public_key -> Signature.Public_key.t tzresult Lwt.t - val public_key_hash : public_key -> Signature.Public_key_hash.t tzresult Lwt.t + val neuterize : sk_uri -> pk_uri tzresult Lwt.t + val public_key : pk_uri -> Signature.Public_key.t tzresult Lwt.t + val public_key_hash : pk_uri -> Signature.Public_key_hash.t tzresult Lwt.t val sign : ?watermark: Signature.watermark -> - secret_key -> MBytes.t -> Signature.t tzresult Lwt.t + sk_uri -> MBytes.t -> Signature.t tzresult Lwt.t end -let signers_table : (string, (module SIGNER) * bool) Hashtbl.t = Hashtbl.create 13 +let signers_table : (string, (module SIGNER)) Hashtbl.t = Hashtbl.create 13 let register_signer signer = let module Signer = (val signer : SIGNER) in - Hashtbl.replace signers_table Signer.scheme (signer, false) + Hashtbl.replace signers_table Signer.scheme signer -let find_signer_for_key cctxt ~scheme = +let find_signer_for_key ~scheme = match Hashtbl.find signers_table scheme with | exception Not_found -> fail (Unregistered_key_scheme scheme) - | signer, false -> - let module Signer = (val signer : SIGNER) in - Signer.init cctxt >>=? fun () -> - Hashtbl.replace signers_table scheme (signer, true) ; - return signer - | signer, true -> return signer + | signer -> return signer let registered_signers () : (string * (module SIGNER)) list = - Hashtbl.fold (fun k (v, _) acc -> (k, v) :: acc) signers_table [] + Hashtbl.fold (fun k v acc -> (k, v) :: acc) signers_table [] -type error += Signature_mismatch of Secret_key_locator.t +type error += Signature_mismatch of sk_uri let () = register_error_kind `Permanent @@ -170,134 +97,87 @@ let () = (fun ppf sk -> Format.fprintf ppf "The signer for %a produced an invalid signature" - Secret_key_locator.pp sk) - Data_encoding.(obj1 (req "locator" Secret_key_locator.encoding)) + Uri.pp_hum sk) + Data_encoding.(obj1 (req "locator" uri_encoding)) (function Signature_mismatch sk -> Some sk | _ -> None) (fun sk -> Signature_mismatch sk) -let sign ?watermark cctxt ((Sk_locator { scheme }) as skloc) buf = - find_signer_for_key cctxt ~scheme >>=? fun signer -> +let neuterize sk_uri = + let scheme = Option.unopt ~default:"" (Uri.scheme sk_uri) in + find_signer_for_key ~scheme >>=? fun signer -> let module Signer = (val signer : SIGNER) in - Signer.sk_of_locator skloc >>=? fun t -> - Signer.sign ?watermark t buf >>=? fun signature -> - Signer.neuterize t >>= fun pk -> - Signer.public_key pk >>=? fun pubkey -> + Signer.neuterize sk_uri + +let public_key pk_uri = + let scheme = Option.unopt ~default:"" (Uri.scheme pk_uri) in + find_signer_for_key ~scheme >>=? fun signer -> + let module Signer = (val signer : SIGNER) in + Signer.public_key pk_uri + +let public_key_hash pk_uri = + public_key pk_uri >>=? fun pk -> + return (Signature.Public_key.hash pk) + +let sign ?watermark sk_uri buf = + let scheme = Option.unopt ~default:"" (Uri.scheme sk_uri) in + find_signer_for_key ~scheme >>=? fun signer -> + let module Signer = (val signer : SIGNER) in + Signer.sign ?watermark sk_uri buf >>=? fun signature -> + Signer.neuterize sk_uri >>=? fun pk_uri -> + public_key pk_uri >>=? fun pubkey -> fail_unless (Signature.check ?watermark pubkey signature buf) - (Signature_mismatch skloc) >>=? fun () -> + (Signature_mismatch sk_uri) >>=? fun () -> return signature -let append ?watermark cctxt loc buf = - sign ?watermark cctxt loc buf >>|? fun signature -> +let append ?watermark loc buf = + sign ?watermark loc buf >>|? fun signature -> Signature.concat buf signature -let register_key cctxt ?(force=false) - (public_key_hash, public_key, secret_key) name = - Secret_key.add ~force cctxt name - (Secret_key_locator.of_unencrypted secret_key) >>=? fun () -> - Public_key.add ~force cctxt name - (Public_key_locator.of_unencrypted public_key) >>=? fun () -> - Public_key_hash.add ~force - cctxt name public_key_hash >>=? fun () -> +let register_key cctxt ?(force=false) (public_key_hash, pk_uri, sk_uri) name = + Public_key.add ~force cctxt name pk_uri >>=? fun () -> + Secret_key.add ~force cctxt name sk_uri >>=? fun () -> + Public_key_hash.add ~force cctxt name public_key_hash >>=? fun () -> return () -let gen_keys ?(force=false) ?algo ?seed (cctxt : #Client_context.io_wallet) name = - let key = Signature.generate_key ?algo ?seed () in - register_key cctxt ~force key name - -let gen_keys_containing ?(prefix=false) ?(force=false) ~containing ~name (cctxt : #Client_context.io_wallet) = - let unrepresentable = - List.filter (fun s -> not @@ Base58.Alphabet.all_in_alphabet Base58.Alphabet.bitcoin s) containing in - match unrepresentable with - | _ :: _ -> - cctxt#warning - "The following can't be written in the key alphabet (%a): %a" - Base58.Alphabet.pp Base58.Alphabet.bitcoin - (Format.pp_print_list - ~pp_sep:(fun ppf () -> Format.fprintf ppf ", ") - (fun ppf s -> Format.fprintf ppf "'%s'" s)) - unrepresentable >>= return - | [] -> - Public_key_hash.mem cctxt name >>=? fun name_exists -> - if name_exists && not force - then - cctxt#warning - "Key for name '%s' already exists. Use -force to update." name >>= return - else - begin - cctxt#warning "This process uses a brute force search and \ - may take a long time to find a key." >>= fun () -> - let matches = - if prefix then - let containing_tz1 = List.map ((^) "tz1") containing in - (fun key -> List.exists - (fun containing -> - String.sub key 0 (String.length containing) = containing) - containing_tz1) - else - let re = Re.Str.regexp (String.concat "\\|" containing) in - (fun key -> try ignore (Re.Str.search_forward re key 0); true - with Not_found -> false) in - let rec loop attempts = - let public_key_hash, public_key, secret_key = - Signature.generate_key () in - let hash = Signature.Public_key_hash.to_b58check @@ - Signature.Public_key.hash public_key in - if matches hash - then - Secret_key.add ~force cctxt name - (Secret_key_locator.of_unencrypted secret_key) >>=? fun () -> - Public_key.add ~force cctxt name - (Public_key_locator.of_unencrypted public_key) >>=? fun () -> - Public_key_hash.add ~force cctxt name public_key_hash >>=? fun () -> - return hash - else begin if attempts mod 25_000 = 0 - then cctxt#message "Tried %d keys without finding a match" attempts - else Lwt.return () end >>= fun () -> - loop (attempts + 1) in - loop 1 >>=? fun key_hash -> - cctxt#message - "Generated '%s' under the name '%s'." key_hash name >>= fun () -> - return () - end - -let get_key (cctxt : #Client_context.wallet) pkh = +let raw_get_key (cctxt : #Client_context.wallet) pkh = Public_key_hash.rev_find cctxt pkh >>=? function | None -> failwith "no keys for the source contract manager" | Some n -> - Public_key.find cctxt n >>=? fun pk -> - Secret_key.find cctxt n >>=? fun sk -> - let scheme = Secret_key_locator.scheme sk in - find_signer_for_key cctxt ~scheme >>=? fun signer -> - let module Signer = (val signer : SIGNER) in - Signer.pk_of_locator pk >>=? fun pk -> - Signer.public_key pk >>=? fun pk -> - return (n, pk, sk) + Public_key.find_opt cctxt n >>=? fun pk_uri -> + Secret_key.find_opt cctxt n >>=? fun sk_uri -> + begin + Option.unopt_map + ~default:Lwt.return_none + ~f:(fun pkh -> + public_key pkh >>= function + | Error e -> + Format.eprintf "PLOP: %a@." pp_print_error e ; + Lwt.return_none + | Ok pk -> Lwt.return_some pk) + pk_uri + end >>= fun pk -> + return (n, pk, sk_uri) -let get_public_key (cctxt : #Client_context.wallet) pkh = - Public_key_hash.rev_find cctxt pkh >>=? function - | None -> failwith "no keys for the source contract manager" - | Some n -> - Public_key.find cctxt n >>=? fun pk -> - let scheme = Public_key_locator.scheme pk in - find_signer_for_key cctxt ~scheme >>=? fun signer -> - let module Signer = (val signer : SIGNER) in - Signer.pk_of_locator pk >>=? fun pk -> - Signer.public_key pk >>=? fun pk -> - return (n, pk) +let get_key cctxt pkh = + raw_get_key cctxt pkh >>=? function + | (pkh, Some pk, Some sk) -> return (pkh, pk, sk) + | (_pkh, _pk, None) -> failwith "... FIXME ... E" + | (_pkh, None, _sk) -> failwith "... FIXME ... F" -let get_keys (wallet : #Client_context.io_wallet) = - Secret_key.load wallet >>=? fun sks -> - Lwt_list.filter_map_s begin fun (name, sk) -> +let get_public_key cctxt pkh = + raw_get_key cctxt pkh >>=? function + | (pkh, Some pk, _sk) -> return (pkh, pk) + | (_pkh, None, _sk) -> failwith "... FIXME ... G" + +let get_keys (cctxt : #Client_context.wallet) = + Secret_key.load cctxt >>=? fun sks -> + Lwt_list.filter_map_s begin fun (name, sk_uri) -> begin - Public_key.find wallet name >>=? fun pk -> - Public_key_hash.find wallet name >>=? fun pkh -> - let scheme = Public_key_locator.scheme pk in - find_signer_for_key wallet ~scheme >>=? fun signer -> - let module Signer = (val signer : SIGNER) in - Signer.pk_of_locator pk >>=? fun pk -> - Signer.public_key pk >>=? fun pk -> - return (name, pkh, pk, sk) + Public_key.find cctxt name >>=? fun pk_uri -> + Public_key_hash.find cctxt name >>=? fun pkh -> + public_key pk_uri >>=? fun pk -> + return (name, pkh, pk, sk_uri) end >>= function | Ok r -> Lwt.return (Some r) | Error _ -> Lwt.return_none @@ -308,24 +188,18 @@ let list_keys cctxt = Public_key_hash.load cctxt >>=? fun l -> map_s (fun (name, pkh) -> - Public_key.find_opt cctxt name >>=? fun pkm -> - Secret_key.find_opt cctxt name >>=? fun pks -> - return (name, pkh, pkm, pks)) + raw_get_key cctxt pkh >>= function + | Ok (_name, pk, sk_uri) -> + return (name, pkh, pk, sk_uri) + | Error _ -> + return (name, pkh, None, None)) l let alias_keys cctxt name = - Public_key_hash.load cctxt >>=? fun l -> - let rec find_key = function - | [] -> return None - | (key_name, pkh) :: tl -> - if key_name = name - then begin - Public_key.find_opt cctxt name >>=? fun pkm -> - Secret_key.find_opt cctxt name >>=? fun pks -> - return (Some (pkh, pkm, pks)) - end - else find_key tl - in find_key l + Public_key_hash.find cctxt name >>=? fun pkh -> + raw_get_key cctxt pkh >>= function + | Ok (_name, pk, sk_uri) -> return (Some (pkh, pk, sk_uri)) + | Error _ -> return None let force_switch () = Clic.switch diff --git a/src/lib_client_base/client_keys.mli b/src/lib_client_base/client_keys.mli index b2fe5c420..be7b0a840 100644 --- a/src/lib_client_base/client_keys.mli +++ b/src/lib_client_base/client_keys.mli @@ -7,28 +7,11 @@ (* *) (**************************************************************************) -(** {2 Location of keys using schemes} *) - -type location = string list -type sk_uri = Sk_locator of { scheme : string ; location : location } -type pk_uri = Pk_locator of { scheme : string ; location : location } - -module type LOCATOR = sig - val name : string - type t - - val create : scheme:string -> location:location -> t - val scheme : t -> string - val location : t -> location - val to_string : t -> string - val pp : Format.formatter -> t -> unit -end - -module Secret_key_locator : LOCATOR with type t = sk_uri -module Public_key_locator : LOCATOR with type t = pk_uri - (** {2 Cryptographic keys tables } *) +type pk_uri = private Uri.t +type sk_uri = private Uri.t + module Public_key_hash : Client_aliases.Alias with type t = Signature.Public_key_hash.t module Public_key : @@ -39,8 +22,6 @@ module Secret_key : (** {2 Interface for external signing modules.} *) module type SIGNER = sig - type secret_key - type public_key val scheme : string (** [scheme] is the name of the scheme implemented by this signer @@ -53,47 +34,18 @@ module type SIGNER = sig (** [description] is a multi-line human readable description of the signer, that should include the format of key specifications. *) - val init : - #Client_context.io_wallet -> unit tzresult Lwt.t - (** [init wallet] initialized the signer module (plugin - dependent). *) - - val sk_locator_of_human_input : - #Client_context.io_wallet -> string list -> sk_uri tzresult Lwt.t - (** [sk_locator_of_human_input wallet spec] is the [sk_locator] - corresponding to the human readable specification [spec] (plugin - dependent). *) - - val pk_locator_of_human_input : - #Client_context.io_wallet -> string list -> pk_uri tzresult Lwt.t - (** [pk_locator_of_human_input wallet spec] is the [pk_locator] - corresponding to the human readable specification [spec] (plugin - dependent). *) - - val sk_of_locator : sk_uri -> secret_key tzresult Lwt.t - (** [sk_of_locator skloc] is the secret key at [skloc]. *) - - val pk_of_locator : pk_uri -> public_key tzresult Lwt.t - (** [pk_of_locator pkloc] is the public key at [pkloc]. *) - - val sk_to_locator : secret_key -> sk_uri Lwt.t - (** [sk_to_locator sk] is the location of secret key [sk]. *) - - val pk_to_locator : public_key -> pk_uri Lwt.t - (** [pk_to_locator pk] is the location of public key [pk]. *) - - val neuterize : secret_key -> public_key Lwt.t + val neuterize : sk_uri -> pk_uri tzresult Lwt.t (** [neuterize sk] is the corresponding [pk]. *) - val public_key : public_key -> Signature.Public_key.t tzresult Lwt.t + val public_key : pk_uri -> Signature.Public_key.t tzresult Lwt.t (** [public_key pk] is the Ed25519 version of [pk]. *) - val public_key_hash : public_key -> Signature.Public_key_hash.t tzresult Lwt.t + val public_key_hash : pk_uri -> Signature.Public_key_hash.t tzresult Lwt.t (** [public_key_hash pk] is the hash of [pk]. *) val sign : ?watermark: Signature.watermark -> - secret_key -> MBytes.t -> Signature.t tzresult Lwt.t + sk_uri -> MBytes.t -> Signature.t tzresult Lwt.t (** [sign ?watermark sk data] is signature obtained by signing [data] with [sk]. *) end @@ -104,59 +56,51 @@ val register_signer : (module SIGNER) -> unit val registered_signers : unit -> (string * (module SIGNER)) list -val find_signer_for_key : - #Client_context.io_wallet -> scheme:string -> (module SIGNER) tzresult Lwt.t +val public_key : pk_uri -> Signature.Public_key.t tzresult Lwt.t + +val public_key_hash : pk_uri -> Signature.Public_key_hash.t tzresult Lwt.t + +val neuterize : sk_uri -> pk_uri tzresult Lwt.t val sign : ?watermark:Signature.watermark -> - #Client_context.io_wallet -> sk_uri -> MBytes.t -> Signature.t tzresult Lwt.t val append : ?watermark:Signature.watermark -> - #Client_context.io_wallet -> sk_uri -> MBytes.t -> MBytes.t tzresult Lwt.t -val gen_keys : - ?force:bool -> - ?algo:Signature.algo -> - ?seed:MBytes.t -> - #Client_context.io_wallet -> string -> unit tzresult Lwt.t - val register_key : #Client_context.wallet -> ?force:bool -> - (Signature.Public_key_hash.t * - Signature.Public_key.t * - Signature.Secret_key.t) -> string -> unit tzresult Lwt.t - -val gen_keys_containing : - ?prefix:bool -> - ?force:bool -> - containing:string list -> - name:string -> - #Client_context.io_wallet -> unit tzresult Lwt.t + (Signature.Public_key_hash.t * pk_uri * sk_uri) -> string -> unit tzresult Lwt.t val list_keys : #Client_context.wallet -> - (string * Public_key_hash.t * pk_uri option * sk_uri option) list tzresult Lwt.t + (string * Public_key_hash.t * Signature.public_key option * sk_uri option) list tzresult Lwt.t val alias_keys : #Client_context.wallet -> string -> - (Public_key_hash.t * pk_uri option * sk_uri option) option tzresult Lwt.t + (Public_key_hash.t * Signature.public_key option * sk_uri option) option tzresult Lwt.t -val get_key: - #Client_context.io_wallet -> +val get_key : + #Client_context.wallet -> Public_key_hash.t -> (string * Signature.Public_key.t * sk_uri) tzresult Lwt.t -val get_public_key: - #Client_context.io_wallet -> +val get_public_key : + #Client_context.wallet -> Public_key_hash.t -> (string * Signature.Public_key.t) tzresult Lwt.t val get_keys: - #Client_context.io_wallet -> + #Client_context.wallet -> (string * Public_key_hash.t * Signature.Public_key.t * sk_uri) list tzresult Lwt.t val force_switch : unit -> (bool, 'ctx) Clic.arg + +(**/**) + +val make_pk_uri : Uri.t -> pk_uri +val make_sk_uri : Uri.t -> sk_uri + diff --git a/src/lib_client_base_unix/client_main_run.ml b/src/lib_client_base_unix/client_main_run.ml index d56e05ff8..998d0cace 100644 --- a/src/lib_client_base_unix/client_main_run.ml +++ b/src/lib_client_base_unix/client_main_run.ml @@ -77,9 +77,15 @@ let main select_commands = Client_keys.register_signer (module Tezos_signer_backends.Unencrypted) ; Client_keys.register_signer - (module Tezos_signer_backends.Encrypted) ; + (module Tezos_signer_backends.Encrypted.Make(struct + let cctxt = new Client_context_unix.unix_prompter + end)) ; Client_keys.register_signer - (module Tezos_signer_backends.Remote) ; + (module Tezos_signer_backends.Https) ; + Client_keys.register_signer + (module Tezos_signer_backends.Socket.Unix) ; + Client_keys.register_signer + (module Tezos_signer_backends.Socket.Tcp) ; Lwt.catch begin fun () -> begin Client_config.parse_config_args (new unix_full diff --git a/src/lib_client_commands/client_keys_commands.ml b/src/lib_client_commands/client_keys_commands.ml index 863511369..4d5748a11 100644 --- a/src/lib_client_commands/client_keys_commands.ml +++ b/src/lib_client_commands/client_keys_commands.ml @@ -22,7 +22,64 @@ let sig_algo_arg = ~default: "ed25519" (Signature.algo_param ()) -let commands () = +let gen_keys_containing + ?(prefix=false) ?(force=false) + ~containing ~name (cctxt : #Client_context.io_wallet) = + let unrepresentable = + List.filter (fun s -> not @@ Base58.Alphabet.all_in_alphabet Base58.Alphabet.bitcoin s) containing in + match unrepresentable with + | _ :: _ -> + cctxt#warning + "The following can't be written in the key alphabet (%a): %a" + Base58.Alphabet.pp Base58.Alphabet.bitcoin + (Format.pp_print_list + ~pp_sep:(fun ppf () -> Format.fprintf ppf ", ") + (fun ppf s -> Format.fprintf ppf "'%s'" s)) + unrepresentable >>= return + | [] -> + Public_key_hash.mem cctxt name >>=? fun name_exists -> + if name_exists && not force + then + cctxt#warning + "Key for name '%s' already exists. Use -force to update." name >>= return + else + begin + cctxt#warning "This process uses a brute force search and \ + may take a long time to find a key." >>= fun () -> + let matches = + if prefix then + let containing_tz1 = List.map ((^) "tz1") containing in + (fun key -> List.exists + (fun containing -> + String.sub key 0 (String.length containing) = containing) + containing_tz1) + else + let re = Re.Str.regexp (String.concat "\\|" containing) in + (fun key -> try ignore (Re.Str.search_forward re key 0); true + with Not_found -> false) in + let rec loop attempts = + let public_key_hash, public_key, secret_key = + Signature.generate_key () in + let hash = Signature.Public_key_hash.to_b58check @@ + Signature.Public_key.hash public_key in + if matches hash + then + let pk_uri = Tezos_signer_backends.Unencrypted.make_pk public_key in + let sk_uri = Tezos_signer_backends.Unencrypted.make_sk secret_key in + register_key cctxt ~force + (public_key_hash, pk_uri, sk_uri) name >>=? fun () -> + return hash + else begin if attempts mod 25_000 = 0 + then cctxt#message "Tried %d keys without finding a match" attempts + else Lwt.return () end >>= fun () -> + loop (attempts + 1) in + loop 1 >>=? fun key_hash -> + cctxt#message + "Generated '%s' under the name '%s'." key_hash name >>= fun () -> + return () + end + +let commands () : Client_context.io_wallet Clic.command list = let open Clic in let show_private_switch = switch @@ -61,7 +118,10 @@ let commands () = @@ stop) (fun (force, algo) name (cctxt : #Client_context.io_wallet) -> Secret_key.of_fresh cctxt force name >>=? fun name -> - gen_keys ~force ~algo cctxt name) ; + let (pkh, pk, sk) = Signature.generate_key ~algo () in + let pk_uri = Tezos_signer_backends.Unencrypted.make_pk pk in + let sk_uri = Tezos_signer_backends.Unencrypted.make_sk sk in + register_key cctxt ~force (pkh, pk_uri, sk_uri) name) ; command ~group ~desc: "Generate (unencrypted) keys including the given string." (args2 @@ -82,69 +142,53 @@ let commands () = command ~group ~desc: "Add a secret key to the wallet." (args1 (Secret_key.force_switch ())) (prefix "import" - @@ string - ~name:"scheme" - ~desc:"signer to use for this secret key\n\ - Use command `list signing schemes` for a list of \ - supported signers." @@ prefixes [ "secret" ; "key" ] @@ Secret_key.fresh_alias_param - @@ seq_of_param - (string - ~name:"spec" - ~desc:"secret key specification\n\ - Varies from one scheme to the other.\n\ - Use command `list signing schemes` for more \ - information.")) - (fun force scheme name spec cctxt -> + @@ param + ~name:"uri" + ~desc:"secret key\n\ + Varies from one scheme to the other.\n\ + Use command `list signing schemes` for more \ + information." + (parameter (fun _ s -> + try return (Client_keys.make_sk_uri @@ Uri.of_string s) + with Failure s -> failwith "Error while parsing uri: %s" s)) + @@ stop) + (fun force name sk_uri (cctxt : Client_context.io_wallet) -> Secret_key.of_fresh cctxt force name >>=? fun name -> - find_signer_for_key ~scheme cctxt >>=? fun signer -> - let module Signer = (val signer : SIGNER) in - Signer.sk_locator_of_human_input - (cctxt :> Client_context.io_wallet) spec >>=? fun skloc -> - Signer.sk_of_locator skloc >>=? fun sk -> - Signer.neuterize sk >>= fun pk -> - Signer.pk_to_locator pk >>= fun pkloc -> - Public_key.find_opt cctxt name >>=? function - | None -> - Signer.public_key_hash pk >>=? fun pkh -> - Secret_key.add ~force cctxt name skloc >>=? fun () -> - Public_key_hash.add ~force cctxt name pkh >>=? fun () -> - Public_key.add ~force cctxt name pkloc - | Some pk -> - fail_unless (pkloc = pk || force) - (failure - "public and secret keys '%s' don't correspond, \ - please don't use -force" name) >>=? fun () -> - Secret_key.add ~force cctxt name skloc) ; + Client_keys.neuterize sk_uri >>=? fun pk_uri -> + begin + Public_key.find_opt cctxt name >>=? function + | None -> return () + | Some pk -> + fail_unless (pk_uri = pk || force) + (failure + "public and secret keys '%s' don't correspond, \ + please don't use -force" name) + end >>=? fun () -> + Client_keys.public_key_hash pk_uri >>=? fun pkh -> + register_key cctxt ~force (pkh, pk_uri, sk_uri) name) ; command ~group ~desc: "Add a public key to the wallet." (args1 (Public_key.force_switch ())) (prefix "import" - @@ string - ~name:"scheme" - ~desc:"signer to use for this public key\n\ - Use command `list signing schemes` for a list of \ - supported signers." @@ prefixes [ "public" ; "key" ] @@ Public_key.fresh_alias_param - @@ seq_of_param - (string - ~name:"spec" - ~desc:"public key specification\n\ - Varies from one scheme to the other.\n\ - Use command `list signing schemes` for more \ - information.")) - (fun force scheme name location cctxt -> + @@ param + ~name:"uri" + ~desc:"public key\n\ + Varies from one scheme to the other.\n\ + Use command `list signing schemes` for more \ + information." + (parameter (fun _ s -> + try return (Client_keys.make_pk_uri @@ Uri.of_string s) + with Failure s -> failwith "Error while parsing uri: %s" s)) + @@ stop) + (fun force name pk_uri (cctxt : Client_context.io_wallet) -> Public_key.of_fresh cctxt force name >>=? fun name -> - find_signer_for_key ~scheme cctxt >>=? fun signer -> - let module Signer = (val signer : SIGNER) in - Signer.pk_locator_of_human_input - (cctxt :> Client_context.io_wallet) location >>=? fun pkloc -> - Signer.pk_of_locator pkloc >>=? fun pk -> - Signer.public_key_hash pk >>=? fun pkh -> + Client_keys.public_key_hash pk_uri >>=? fun pkh -> Public_key_hash.add ~force cctxt name pkh >>=? fun () -> - Public_key.add ~force cctxt name pkloc) ; + Public_key.add ~force cctxt name pk_uri) ; command ~group ~desc: "Add an identity to the wallet." (args1 (Public_key.force_switch ())) @@ -166,10 +210,13 @@ let commands () = begin match pk, sk with | None, None -> cctxt#message "%s: %s" name v - | _, Some Sk_locator { scheme } -> + | _, Some uri -> + let scheme = + Option.unopt ~default:"unencrypted" @@ + Uri.scheme (uri : sk_uri :> Uri.t) in cctxt#message "%s: %s (%s sk known)" name v scheme - | Some Pk_locator { scheme }, _ -> - cctxt#message "%s: %s (%s pk known)" name v scheme + | Some _, _ -> + cctxt#message "%s: %s (pk known)" name v end >>= fun () -> return () end l) ; @@ -179,36 +226,35 @@ let commands () = @@ Public_key_hash.alias_param @@ stop) (fun show_private (name, _) (cctxt : #Client_context.io_wallet) -> - let ok_lwt x = x >>= (fun x -> return x) in alias_keys cctxt name >>=? fun key_info -> match key_info with - | None -> ok_lwt @@ cctxt#message "No keys found for identity" + | None -> + cctxt#message "No keys found for identity" >>= fun () -> + return () | Some (pkh, pk, skloc) -> - ok_lwt @@ cctxt#message "Hash: %a" - Signature.Public_key_hash.pp pkh >>=? fun () -> + cctxt#message "Hash: %a" + Signature.Public_key_hash.pp pkh >>= fun () -> match pk with | None -> return () - | Some (Pk_locator { scheme } as pkloc) -> - find_signer_for_key ~scheme cctxt >>=? fun signer -> - let module Signer = (val signer : SIGNER) in - Signer.pk_of_locator pkloc >>=? fun pk -> - Signer.public_key pk >>=? fun pk -> - ok_lwt @@ cctxt#message "Public Key: %a" - Signature.Public_key.pp pk >>=? fun () -> + | Some pk -> + cctxt#message "Public Key: %a" + Signature.Public_key.pp pk >>= fun () -> if show_private then match skloc with | None -> return () | Some skloc -> Secret_key.to_source skloc >>=? fun skloc -> - ok_lwt @@ cctxt#message "Secret Key: %s" skloc - else return ()) ; + cctxt#message "Secret Key: %s" skloc >>= fun () -> + return () + else + return ()) ; command ~group ~desc: "Forget the entire wallet of keys." (args1 (Clic.switch ~long:"force" ~short:'f' ~doc:"you got to use the force for that" ())) (fixed [ "forget" ; "all" ; "keys" ]) - (fun force cctxt -> + (fun force (cctxt : Client_context.io_wallet) -> fail_unless force (failure "this can only used with option -force") >>=? fun () -> Public_key.set cctxt [] >>=? fun () -> diff --git a/src/lib_client_commands/jbuild b/src/lib_client_commands/jbuild index 41c0e08db..007aa95f4 100644 --- a/src/lib_client_commands/jbuild +++ b/src/lib_client_commands/jbuild @@ -6,7 +6,8 @@ (libraries (tezos-base tezos-client-base tezos-rpc - tezos-shell-services)) + tezos-shell-services + tezos-signer-backends)) (library_flags (:standard -linkall)) (flags (:standard -w -9+27-30-32-40@8 -safe-string diff --git a/src/lib_signer_backends/encrypted.ml b/src/lib_signer_backends/encrypted.ml index f422def9c..b1e98122e 100644 --- a/src/lib_signer_backends/encrypted.ml +++ b/src/lib_signer_backends/encrypted.ml @@ -11,153 +11,156 @@ open Client_keys let scheme = "encrypted" -let title = - "Built-in signer using encrypted keys." +module Raw = struct -let description = - "If you try to import a secret key without additional argument, you will \ - be asked to either generate a new key, or to import the elements \ - from your fundraiser paper wallet.\n\ - If you add an argument when importing a secret key, \ - the format is the raw Base58-encoded key (starting with 'edsk').\n\ - The format for importing public keys is the raw Base58-encoded \ - key (starting with 'edpk')." + (* https://tools.ietf.org/html/rfc2898#section-4.1 *) + let salt_len = 8 -type secret_key = Signature.Secret_key.t -type public_key = Signature.Public_key.t + (* Fixed zero nonce *) + let nonce = Crypto_box.zero_nonce -(* https://tools.ietf.org/html/rfc2898#section-4.1 *) -let salt_len = 8 + let pbkdf ~salt ~password = + Cstruct.to_bigarray + (Pbkdf.pbkdf2 ~prf:`SHA512 ~count:2048 ~dk_len:32l + ~salt: (Cstruct.of_bigarray salt) + ~password: (Cstruct.of_bigarray password)) -(* Fixed zero nonce *) -let nonce = Crypto_box.zero_nonce + let encrypt ~password sk = + let salt = Rand.generate salt_len in + let key = Crypto_box.Secretbox.unsafe_of_bytes (pbkdf ~password ~salt) in + let msg = Data_encoding.Binary.to_bytes_exn Signature.Secret_key.encoding sk in + let encrypted_passwd = Crypto_box.Secretbox.box key msg nonce in + MBytes.concat "" [ salt ; encrypted_passwd ] -(* skloc -> Signature.Secret_key.t *) -let decrypted_sks = Hashtbl.create 13 + let decrypt ~password ~encrypted_sk = + let len = MBytes.length encrypted_sk in + let salt = MBytes.sub encrypted_sk 0 salt_len in + let encrypted_sk = MBytes.sub encrypted_sk salt_len (len - salt_len) in + let key = Crypto_box.Secretbox.unsafe_of_bytes (pbkdf ~salt ~password) in + match Crypto_box.Secretbox.box_open key encrypted_sk nonce with + | None -> return None + | Some bytes -> + match Data_encoding.Binary.of_bytes Signature.Secret_key.encoding bytes with + | None -> failwith "... FIXME ... D" (* corrupted data *) + | Some sk -> return (Some sk) -let pbkdf ~salt ~password = - let open Cstruct in - let salt = of_bigarray salt in - let password = of_bigarray password in - to_bigarray - (Pbkdf.pbkdf2 ~prf:`SHA512 ~count:2048 ~dk_len:32l ~salt ~password) +end -let rec decrypt_sk sk salt = function - | [] -> None - | password :: pws -> - let key = Crypto_box.Secretbox.unsafe_of_bytes (pbkdf ~password ~salt) in - match Crypto_box.Secretbox.box_open key sk nonce with - | None -> decrypt_sk sk salt pws - | Some sk -> Some sk +let decrypted = Hashtbl.create 13 +let passwords = ref [] -let salt_skenc_of_skloc skloc = - let open Cstruct in - let skloc = of_string skloc in - let len = len skloc in - let salt = sub skloc 0 salt_len in - let skenc = sub skloc salt_len (len - salt_len) in - to_bigarray salt, to_bigarray skenc +let rec interactive_decrypt_loop + (cctxt : #Client_context.prompter) + ?name ~encrypted_sk = + begin + match name with + | None -> + cctxt#prompt_password + "Enter password for encrypted key: " + | Some name -> + cctxt#prompt_password + "Enter password for encrypted key \"%s\": " name + end >>=? fun password -> + Raw.decrypt ~password ~encrypted_sk >>=? function + | None -> + interactive_decrypt_loop cctxt ?name ~encrypted_sk + | Some sk -> + passwords := password :: !passwords ; + return sk -let rec passwd_ask_loop (cctxt : #Client_context.io_wallet) ~name ~salt ~skenc = - cctxt#prompt_password "Enter password for encrypted key %s: " name >>=? fun password -> - let key = pbkdf ~salt ~password in - let key = Crypto_box.Secretbox.unsafe_of_bytes key in - match Crypto_box.Secretbox.box_open key skenc nonce with - | None -> passwd_ask_loop cctxt ~name ~salt ~skenc - | Some decrypted_sk -> - return (password, (Data_encoding.Binary.of_bytes_exn - Signature.Secret_key.encoding - decrypted_sk)) +let rec noninteractice_decrypt_loop ~encrypted_sk = function + | [] -> return None + | password :: passwords -> + Raw.decrypt ~password ~encrypted_sk >>=? function + | None -> noninteractice_decrypt_loop ~encrypted_sk passwords + | Some sk -> return (Some sk) -let ask_all_passwords (cctxt : #Client_context.io_wallet) sks = - fold_left_s begin fun a (name, skloc) -> - if Secret_key_locator.scheme skloc <> scheme then - return a - else - match Secret_key_locator.location skloc with - |location :: _ -> begin - match Base58.safe_decode location with - | None -> Lwt.fail Exit - | Some payload -> - let salt, skenc = salt_skenc_of_skloc payload in - match decrypt_sk skenc salt a with - | Some sk -> - Hashtbl.replace decrypted_sks location - (Data_encoding.Binary.of_bytes_exn Signature.Secret_key.encoding sk); - return a - | None -> - passwd_ask_loop - cctxt ~name ~salt ~skenc >>=? fun (passwd, decrypted_sk) -> - Hashtbl.replace decrypted_sks location decrypted_sk ; - return (passwd :: a) - end - |_ -> Lwt.fail Exit - end [] sks +let decrypt_payload cctxt ?name encrypted_sk = + match Base58.safe_decode encrypted_sk with + | None -> failwith "... FIXME ... A" + | Some encrypted_sk -> + let encrypted_sk = MBytes.of_string encrypted_sk in + noninteractice_decrypt_loop ~encrypted_sk !passwords >>=? function + | Some sk -> return sk + | None -> interactive_decrypt_loop cctxt ?name ~encrypted_sk -let init cctxt = +let decrypt cctxt ?name sk_uri = + let payload = Uri.path (sk_uri : sk_uri :> Uri.t) in + decrypt_payload cctxt ?name payload >>=? fun sk -> + Hashtbl.replace decrypted sk_uri sk ; + return sk + +let decrypt_all (cctxt : #Client_context.io_wallet) = Secret_key.load cctxt >>=? fun sks -> - Lwt.try_bind - (fun () -> ask_all_passwords cctxt sks) - (fun _ -> return ()) - (fun _ -> failwith "Corrupted secret key database. Aborting.") + iter_s begin fun (name, sk_uri) -> + if Uri.scheme (sk_uri : sk_uri :> Uri.t) <> Some scheme then + return () + else + decrypt cctxt ~name sk_uri >>=? fun _ -> + return () + end sks -let input_new_passphrase (cctxt : #Client_context.io_wallet) = - cctxt#prompt_password "Enter passphrase to encrypt your key: " >>=? fun password -> - cctxt#prompt_password "Confirm passphrase: " >>=? fun confirm -> - if password <> confirm then - failwith "Passphrases do not match." - else return password +let rec read_passphrase (cctxt : #Client_context.io) = + cctxt#prompt_password + "Enter passphrase to encrypt your key: " >>=? fun password -> + cctxt#prompt_password + "Confirm passphrase: " >>=? fun confirm -> + if not (MBytes.equal password confirm) then + cctxt#message "Passphrases do not match." >>= fun () -> + read_passphrase cctxt + else + return password -let encrypt_sk cctxt sk = - input_new_passphrase cctxt >>=? fun password -> - let salt = Rand.generate salt_len in - let key = Crypto_box.Secretbox.unsafe_of_bytes (pbkdf ~password ~salt) in - let msg = Data_encoding.Binary.to_bytes_exn Signature.Secret_key.encoding sk in - let encrypted_passwd = Crypto_box.Secretbox.box key msg nonce in - let payload = MBytes.(to_string (concat "" [salt; encrypted_passwd])) in - let location = Base58.safe_encode payload in - Hashtbl.replace decrypted_sks location sk ; - return (Secret_key_locator.create ~scheme ~location:[location]) +let encrypt cctxt sk = + read_passphrase cctxt >>=? fun password -> + let payload = Raw.encrypt ~password sk in + let path = Base58.safe_encode (MBytes.to_string payload) in + let sk_uri = Client_keys.make_sk_uri (Uri.make ~scheme ~path ()) in + Hashtbl.replace decrypted sk_uri sk ; + return sk_uri -let rec get_boolean_answer (cctxt : #Client_context.io_wallet) ~default ~msg = - let prompt = if default then "(Y/n/q)" else "(y/N/q)" in - cctxt#prompt "%s %s: " msg prompt >>=? fun gen -> - match default, String.lowercase_ascii gen with - | default, "" -> return default - | _, "y" -> return true - | _, "n" -> return false - | _, "q" -> failwith "Exit by user request." - | _ -> get_boolean_answer cctxt ~msg ~default +(* -let rec sk_of_mnemonic (cctxt : #Client_context.io_wallet) = - cctxt#prompt "Enter the e-mail used for the paper wallet: " >>=? fun email -> - let rec loop_words acc i = - if i > 14 then return (List.rev acc) else - cctxt#prompt_password "Enter word %d: " i >>=? fun word -> - match Bip39.index_of_word (MBytes.to_string word) with - | None -> loop_words acc i - | Some wordidx -> loop_words (wordidx :: acc) (succ i) in - loop_words [] 0 >>=? fun words -> - match Bip39.of_indices words with - | None -> assert false - | Some t -> - cctxt#prompt_password - "Enter the password used for the paper wallet: " >>=? fun password -> - (* TODO: unicode normalization (NFKD)... *) - let sk = Bip39.to_seed ~passphrase:(email ^ MBytes.to_string password) t in - let sk = Cstruct.(to_bigarray (sub sk 0 32)) in - let sk : Signature.Secret_key.t = - Ed25519 - (Data_encoding.Binary.of_bytes_exn Ed25519.Secret_key.encoding sk) in - let pk = Signature.Secret_key.to_public_key sk in - let pkh = Signature.Public_key.hash pk in - let msg = Format.asprintf - "Your public Tezos address is %a is that correct?" - Signature.Public_key_hash.pp pkh in - get_boolean_answer cctxt ~msg ~default:true >>=? function - | true -> return sk - | false -> sk_of_mnemonic cctxt + let rec get_boolean_answer (cctxt : #Client_context.io_wallet) ~default ~msg = + let prompt = if default then "(Y/n/q)" else "(y/N/q)" in + cctxt#prompt "%s %s: " msg prompt >>= fun gen -> + match default, String.lowercase_ascii gen with + | default, "" -> return default + | _, "y" -> return true + | _, "n" -> return false + | _, "q" -> failwith "Exit by user request." + | _ -> get_boolean_answer cctxt ~msg ~default + let rec sk_of_mnemonic (cctxt : #Client_context.io_wallet) = + cctxt#prompt "Enter the e-mail used for the paper wallet: " >>= fun email -> + let rec loop_words acc i = + if i > 14 then Lwt.return (List.rev acc) else + cctxt#prompt_password "Enter word %d: " i >>= fun word -> + match Bip39.index_of_word word with + | None -> loop_words acc i + | Some wordidx -> loop_words (wordidx :: acc) (succ i) in + loop_words [] 0 >>= fun words -> + match Bip39.of_indices words with + | None -> assert false + | Some t -> + cctxt#prompt_password + "Enter the password used for the paper wallet: " >>= fun password -> + (* TODO: unicode normalization (NFKD)... *) + let sk = Bip39.to_seed ~passphrase:(email ^ password) t in + let sk = Cstruct.(to_bigarray (sub sk 0 32)) in + let sk : Signature.Secret_key.t = + Ed25519 + (Data_encoding.Binary.of_bytes_exn Ed25519.Secret_key.encoding sk) in + let pk = Signature.Secret_key.to_public_key sk in + let pkh = Signature.Public_key.hash pk in + let msg = Format.asprintf + "Your public Tezos address is %a is that correct?" + Signature.Public_key_hash.pp pkh in + get_boolean_answer cctxt ~msg ~default:true >>=? function + | true -> return sk + | false -> sk_of_mnemonic cctxt +*) +(* let sk_locator_of_human_input cctxt = function | sk :: _ -> Lwt.return (Signature.Secret_key.of_b58check sk) >>=? fun sk -> @@ -176,37 +179,38 @@ let sk_locator_of_human_input cctxt = function sk_of_mnemonic cctxt >>=? fun sk -> encrypt_sk cctxt sk end + *) +(* let pk_locator_of_human_input _cctxt = function | [] -> failwith "Missing public key argument." | pk :: _ -> return (Public_key_locator.create ~scheme ~location:[pk]) +*) -let sk_of_locator = function - | (Sk_locator { location = [location] }) -> begin - match Hashtbl.find decrypted_sks location with - | exception Not_found -> failwith "Unknown secret key location." - | sk -> return sk - end - | (Sk_locator { location = _ }) -> - failwith "Wrong location type." -let pk_of_locator = function - |(Pk_locator { location = [location] }) -> - Lwt.return (Signature.Public_key.of_b58check location) - |(Pk_locator { location = _ }) -> - failwith "Wrong location type." +module Make(C : sig val cctxt: Client_context.prompter end) = struct -let sk_to_locator sk = - Secret_key_locator.create - ~scheme ~location:[Signature.Secret_key.to_b58check sk] |> - Lwt.return + let scheme = "encrypted" -let pk_to_locator pk = - Public_key_locator.create - ~scheme ~location:[Signature.Public_key.to_b58check pk] |> - Lwt.return + let title = + "Built-in signer using encrypted keys." -let neuterize x = Lwt.return (Signature.Secret_key.to_public_key x) -let public_key x = return x -let public_key_hash x = return (Signature.Public_key.hash x) -let sign ?watermark t buf = return (Signature.sign ?watermark t buf) + let description = + "If you try to import a secret key without additional argument, you will \ + be asked to either generate a new key, or to import the elements \ + from your fundraiser paper wallet.\n\ + If you add an argument when importing a secret key, \ + the format is the raw Base58-encoded key (starting with 'edsk').\n\ + The format for importing public keys is the raw Base58-encoded \ + key (starting with 'edpk')." + + let public_key = Unencrypted.public_key + let public_key_hash = Unencrypted.public_key_hash + let neuterize sk_uri = + decrypt C.cctxt sk_uri >>=? fun sk -> + return (Unencrypted.make_pk (Signature.Secret_key.to_public_key sk)) + let sign ?watermark sk_uri buf = + decrypt C.cctxt sk_uri >>=? fun sk -> + return (Signature.sign ?watermark sk buf) + +end diff --git a/src/lib_signer_backends/encrypted.mli b/src/lib_signer_backends/encrypted.mli index ab4fbe3b2..54f4d5bff 100644 --- a/src/lib_signer_backends/encrypted.mli +++ b/src/lib_signer_backends/encrypted.mli @@ -7,4 +7,16 @@ (* *) (**************************************************************************) -include Client_keys.SIGNER +module Make(C : sig val cctxt: Client_context.prompter end) : Client_keys.SIGNER + +val decrypt: + #Client_context.io_wallet -> + ?name:string -> + Client_keys.sk_uri -> Signature.secret_key tzresult Lwt.t + +val decrypt_all: + #Client_context.io_wallet -> unit tzresult Lwt.t + +val encrypt: + #Client_context.io -> + Signature.secret_key -> Client_keys.sk_uri tzresult Lwt.t diff --git a/src/lib_signer_backends/https.ml b/src/lib_signer_backends/https.ml new file mode 100644 index 000000000..c9634258f --- /dev/null +++ b/src/lib_signer_backends/https.ml @@ -0,0 +1,49 @@ +(**************************************************************************) +(* *) +(* Copyright (c) 2014 - 2018. *) +(* Dynamic Ledger Solutions, Inc. *) +(* *) +(* All rights reserved. No warranty, explicit or implicit, provided. *) +(* *) +(**************************************************************************) + +open Client_keys + +let scheme = "https" + +let title = "..." + +let description = "..." + +let parse uri = + let path = String.split '/' (Uri.path uri) in + match List.rev path with + | [] -> invalid_arg "..." + | key :: rev_path -> + Lwt.return (Signature.Public_key_hash.of_b58check key) >>=? fun key -> + return (Uri.with_path uri (String.concat "/" (List.rev rev_path)), + key) + +let public_key uri = + parse (uri : pk_uri :> Uri.t) >>=? fun (base, pkh) -> + RPC_client.call_service + Media_type.all_media_types + ~base Signer_services.public_key ((), pkh) () () + +let neuterize uri = + return (Client_keys.make_pk_uri (uri : sk_uri :> Uri.t)) + +let public_key_hash uri = + public_key uri >>=? fun pk -> + return (Signature.Public_key.hash pk) + +let sign ?watermark uri msg = + parse (uri : sk_uri :> Uri.t) >>=? fun (base, pkh) -> + let msg = + match watermark with + | None -> msg + | Some watermark -> + MBytes.concat "" [ Signature.bytes_of_watermark watermark ; msg ] in + RPC_client.call_service + Media_type.all_media_types + ~base Signer_services.sign ((), pkh) () msg diff --git a/src/lib_signer_backends/remote.mli b/src/lib_signer_backends/https.mli similarity index 90% rename from src/lib_signer_backends/remote.mli rename to src/lib_signer_backends/https.mli index ab4fbe3b2..36af65b63 100644 --- a/src/lib_signer_backends/remote.mli +++ b/src/lib_signer_backends/https.mli @@ -1,6 +1,6 @@ (**************************************************************************) (* *) -(* Copyright (c) 2014 - 2017. *) +(* Copyright (c) 2014 - 2018. *) (* Dynamic Ledger Solutions, Inc. *) (* *) (* All rights reserved. No warranty, explicit or implicit, provided. *) diff --git a/src/lib_signer_backends/jbuild b/src/lib_signer_backends/jbuild index b694ab211..f701e81a0 100644 --- a/src/lib_signer_backends/jbuild +++ b/src/lib_signer_backends/jbuild @@ -14,8 +14,7 @@ -open Tezos_stdlib_unix -open Tezos_client_base -open Tezos_signer_services - -open Tezos_rpc_http - -w -9)))) + -open Tezos_rpc_http)))) (alias ((name runtest_indent) diff --git a/src/lib_signer_backends/remote.ml b/src/lib_signer_backends/remote.ml deleted file mode 100644 index 195f8d194..000000000 --- a/src/lib_signer_backends/remote.ml +++ /dev/null @@ -1,172 +0,0 @@ -(**************************************************************************) -(* *) -(* Copyright (c) 2014 - 2018. *) -(* Dynamic Ledger Solutions, Inc. *) -(* *) -(* All rights reserved. No warranty, explicit or implicit, provided. *) -(* *) -(**************************************************************************) - -open Client_keys -open Signer_messages - -type path = - | Socket of Lwt_utils_unix.Socket.addr - | Https of string * int - -let socket_sign path pkh data = - let req = { Sign.Request.pkh ; data } in - Lwt_utils_unix.Socket.connect path >>=? fun conn -> - Lwt_utils_unix.Socket.send conn Request.encoding (Request.Sign req) >>=? fun () -> - let encoding = result_encoding Sign.Response.encoding in - Lwt_utils_unix.Socket.recv conn encoding >>=? fun res -> - Lwt_unix.close conn >>= fun () -> - Lwt.return res - -let socket_request_public_key path pkh = - Lwt_utils_unix.Socket.connect path >>=? fun conn -> - Lwt_utils_unix.Socket.send conn Request.encoding (Request.Public_key pkh) >>=? fun () -> - let encoding = result_encoding Public_key.Response.encoding in - Lwt_utils_unix.Socket.recv conn encoding >>=? fun res -> - Lwt_unix.close conn >>= fun () -> - Lwt.return res - -let sign path pkh data = - match path with - | Socket path -> socket_sign path pkh data - | Https (host, port) -> - RPC_client.call_service - Media_type.all_media_types - ~base: (Uri.of_string (Format.asprintf "https://%s:%d" host port)) - Signer_services.sign ((), pkh) () data - -let request_public_key path pkh = - match path with - | Socket path -> socket_request_public_key path pkh - | Https (host, port) -> - RPC_client.call_service - Media_type.all_media_types - ~base: (Uri.of_string (Format.asprintf "https://%s:%d" host port)) - Signer_services.public_key ((), pkh) () () - -module Remote_signer : SIGNER = struct - let scheme = "remote" - - let title = - "Built-in tezos-signer using remote wallet." - - let description = - "Valid locators are one of these two forms:\n\ - \ - unix [path to local signer socket] \n\ - \ - tcp [host] [port] \n\ - \ - https [host] [port] \n\ - All fields except the key can be of the form '$VAR', \ - in which case their value is taken from environment variable \ - VAR each time the key is accessed.\n\ - Not specifiyng fields sets them to $TEZOS_SIGNER_UNIX_PATH, \ - $TEZOS_SIGNER_TCP_HOST and $TEZOS_SIGNER_TCP_PORT, \ - $TEZOS_SIGNER_HTTPS_HOST and $TEZOS_SIGNER_HTTPS_PORT, \ - that get evaluated to default values '$HOME/.tezos-signer-socket', \ - localhost and 6732, and can be set later on." - - type key_path = path * Signature.Public_key_hash.t - - (* secret key is the identifier of the location key identifier *) - type secret_key = key_path - (* public key is the identifier of the location key identifier *) - type public_key = key_path * Signature.Public_key.t - - let pks : (secret_key, Signature.Public_key.t) Hashtbl.t = Hashtbl.create 53 - - (* load and init the remote wallet. initialize the connection *) - let init _cctxt = return () - - let path_of_human_input = function - | "unix" :: key :: [] -> - return (Socket (Unix "$TEZOS_SIGNER_UNIX_PATH"), - Signature.Public_key_hash.of_b58check_exn key) - | "unix" :: file :: key :: [] -> - return (Socket (Unix file), - Signature.Public_key_hash.of_b58check_exn key) - | "tcp" :: host :: port :: key :: [] -> - return (Socket (Tcp (host, int_of_string port)), - Signature.Public_key_hash.of_b58check_exn key) - (* Temporary FIXME *) - (* | "tcp" :: host :: key :: [] -> *) - (* return (Socket (Tcp (host, "$TEZOS_SIGNER_TCP_PORT")), key) *) - (* | "tcp" :: key :: [] -> *) - (* return (Socket (Tcp ("$TEZOS_SIGNER_TCP_HOST", "$TEZOS_SIGNER_TCP_PORT")), key) *) - | "https" :: host :: port :: key :: [] -> - return (Https (host, int_of_string port), - Signature.Public_key_hash.of_b58check_exn key) - (* Temporary FIXME *) - (* | "https" :: host :: key :: [] -> *) - (* return (Https (host, "$TEZOS_SIGNER_HTTPS_PORT"), key) *) - (* | "https" :: key :: [] -> *) - (* return (Https ("$TEZOS_SIGNER_HTTPS_HOST", "$TEZOS_SIGNER_HTTPS_PORT"), key) *) - | location -> - failwith - "@[Remote Schema : wrong locator %s.@,@[%a@]@]" - (Secret_key_locator.to_string (Secret_key_locator.create ~scheme ~location)) - Format.pp_print_text description - - let locator_of_path = function - | Socket (Unix path), key -> [ "unix" ; path ; Signature.Public_key_hash.to_b58check key ] - | Socket (Tcp (host, port)), key -> [ "tcp" ; host ; string_of_int port ; Signature.Public_key_hash.to_b58check key ] - | Https (host, port), key -> [ "https" ; host ; string_of_int port ; Signature.Public_key_hash.to_b58check key ] - - let pk_locator_of_human_input _cctxt path = - path_of_human_input path >>=? fun pk -> - let location = locator_of_path pk in - return (Public_key_locator.create ~scheme ~location) - - let sk_to_locator sk = - let location = locator_of_path sk in - Lwt.return (Secret_key_locator.create ~scheme ~location) - - let sk_locator_of_human_input _cctxt input = - path_of_human_input input >>=? fun (path, key) -> - request_public_key path key >>=? fun pk -> - Hashtbl.replace pks (path, key) pk ; - sk_to_locator (path,key) >>= fun locator -> - return locator - - let sk_of_locator loc = - path_of_human_input (Secret_key_locator.location loc) - - let pk_of_locator loc = - path_of_human_input (Public_key_locator.location loc) >>=? fun (path, key) -> - request_public_key path key >>=? fun pk -> - Hashtbl.replace pks (path, key) pk ; - return ((path, key), pk) - - let pk_to_locator (path, _) = - let location = locator_of_path path in - Lwt.return (Public_key_locator.create ~scheme ~location) - - let neuterize ((path, key) as sk) = - match Hashtbl.find_opt pks sk with - | Some pk -> Lwt.return (sk, pk) - | None -> begin - request_public_key path key >>= function - | Error _ -> Lwt.fail_with "Remote : Cannot obtain public key from remote signer" - | Ok pk -> begin - Hashtbl.replace pks sk pk ; - Lwt.return (sk, pk) - end - end - - let public_key (_, x) = return x - let public_key_hash (_, x) = return (Signature.Public_key.hash x) - - let sign ?watermark (path, key) msg = - let msg = - match watermark with - | None -> msg - | Some watermark -> - MBytes.concat "" [ Signature.bytes_of_watermark watermark ; msg ] in - sign path key msg - -end - -include Remote_signer diff --git a/src/lib_signer_backends/socket.ml b/src/lib_signer_backends/socket.ml new file mode 100644 index 000000000..d9826a38f --- /dev/null +++ b/src/lib_signer_backends/socket.ml @@ -0,0 +1,105 @@ +(**************************************************************************) +(* *) +(* Copyright (c) 2014 - 2018. *) +(* Dynamic Ledger Solutions, Inc. *) +(* *) +(* All rights reserved. No warranty, explicit or implicit, provided. *) +(* *) +(**************************************************************************) + +open Client_keys +open Signer_messages + +let sign ?watermark path pkh msg = + let msg = + match watermark with + | None -> msg + | Some watermark -> + MBytes.concat "" [ Signature.bytes_of_watermark watermark ; msg ] in + let req = { Sign.Request.pkh ; data = msg } in + Lwt_utils_unix.Socket.connect path >>=? fun conn -> + Lwt_utils_unix.Socket.send + conn Request.encoding (Request.Sign req) >>=? fun () -> + let encoding = result_encoding Sign.Response.encoding in + Lwt_utils_unix.Socket.recv conn encoding >>=? fun res -> + Lwt_unix.close conn >>= fun () -> + Lwt.return res + +let public_key path pkh = + Lwt_utils_unix.Socket.connect path >>=? fun conn -> + Lwt_utils_unix.Socket.send + conn Request.encoding (Request.Public_key pkh) >>=? fun () -> + let encoding = result_encoding Public_key.Response.encoding in + Lwt_utils_unix.Socket.recv conn encoding >>=? fun res -> + Lwt_unix.close conn >>= fun () -> + Lwt.return res + +module Unix = struct + + let scheme = "unix" + + let title = "..." + + let description = "..." + + let parse uri = + match Uri.get_query_param uri "key" with + | None -> invalid_arg "... FIXME ... B" + | Some key -> + Lwt.return (Signature.Public_key_hash.of_b58check key) >>=? fun key -> + return (Lwt_utils_unix.Socket.Unix (Uri.path uri), key) + + let public_key uri = + parse (uri : pk_uri :> Uri.t) >>=? fun (path, pkh) -> + public_key path pkh + + let neuterize uri = + return (Client_keys.make_pk_uri (uri : sk_uri :> Uri.t)) + + let public_key_hash uri = + public_key uri >>=? fun pk -> + return (Signature.Public_key.hash pk) + + let sign ?watermark uri msg = + parse (uri : sk_uri :> Uri.t) >>=? fun (path, pkh) -> + sign ?watermark path pkh msg + +end + +module Tcp = struct + + let scheme = "tcp" + + let title = "..." + + let description = "..." + + (* let init _cctxt = return () *) + + let parse uri = + match Uri.get_query_param uri "key" with + | None -> invalid_arg "... FIXME ... C" + | Some key -> + Lwt.return (Signature.Public_key_hash.of_b58check key) >>=? fun key -> + match Uri.host uri, Uri.port uri with + | None, _ | _, None -> + invalid_arg "... FIXME ... C2" + | Some path, Some port -> + return (Lwt_utils_unix.Socket.Tcp (path, port), key) + + let public_key uri = + parse (uri : pk_uri :> Uri.t) >>=? fun (path, pkh) -> + public_key path pkh + + let neuterize uri = + return (Client_keys.make_pk_uri (uri : sk_uri :> Uri.t)) + + let public_key_hash uri = + public_key uri >>=? fun pk -> + return (Signature.Public_key.hash pk) + + let sign ?watermark uri msg = + parse (uri : sk_uri :> Uri.t) >>=? fun (path, pkh) -> + sign ?watermark path pkh msg + +end diff --git a/src/lib_signer_backends/socket.mli b/src/lib_signer_backends/socket.mli new file mode 100644 index 000000000..41cc3417d --- /dev/null +++ b/src/lib_signer_backends/socket.mli @@ -0,0 +1,11 @@ +(**************************************************************************) +(* *) +(* Copyright (c) 2014 - 2018. *) +(* Dynamic Ledger Solutions, Inc. *) +(* *) +(* All rights reserved. No warranty, explicit or implicit, provided. *) +(* *) +(**************************************************************************) + +module Unix : Client_keys.SIGNER +module Tcp : Client_keys.SIGNER diff --git a/src/lib_signer_backends/unencrypted.ml b/src/lib_signer_backends/unencrypted.ml index 43f6be584..f9a0826c7 100644 --- a/src/lib_signer_backends/unencrypted.ml +++ b/src/lib_signer_backends/unencrypted.ml @@ -22,11 +22,7 @@ let description = The format for importing public keys is the raw Base58-encoded \ key (starting with 'edpk')." -type secret_key = Signature.Secret_key.t -type public_key = Signature.Public_key.t - -let init _wallet = return () - +(* let sk_locator_of_human_input _cctxt = function | sk :: _ -> return (Secret_key_locator.create ~scheme ~location:[sk]) @@ -39,30 +35,31 @@ let pk_locator_of_human_input _cctxt = function | [] -> failwith "Missing public key argument" | pk :: _ -> return (Public_key_locator.create ~scheme ~location:[pk]) -let sk_of_locator = function - |(Sk_locator { location = ( location :: _ ) }) -> - Lwt.return (Signature.Secret_key.of_b58check location) - |(Sk_locator { location = _ }) -> - failwith "Wrong type of location" - - -let pk_of_locator = function - |(Pk_locator { location = ( location :: _ ) }) -> - Lwt.return (Signature.Public_key.of_b58check location) - |(Pk_locator { location = _ }) -> - failwith "Wrong type of location" - -let sk_to_locator sk = - Secret_key_locator.create - ~scheme ~location:[Signature.Secret_key.to_b58check sk] |> +*) +let secret_key sk_uri = Lwt.return + (Signature.Secret_key.of_b58check (Uri.path (sk_uri : sk_uri :> Uri.t))) -let pk_to_locator pk = - Public_key_locator.create - ~scheme ~location:[Signature.Public_key.to_b58check pk] |> +let make_sk sk = + Client_keys.make_sk_uri + (Uri.make ~scheme ~path:(Signature.Secret_key.to_b58check sk) ()) + +let public_key pk_uri = Lwt.return + (Signature.Public_key.of_b58check (Uri.path (pk_uri : pk_uri :> Uri.t))) -let neuterize x = Lwt.return (Signature.Secret_key.to_public_key x) -let public_key x = return x -let public_key_hash x = return (Signature.Public_key.hash x) -let sign ?watermark t buf = return (Signature.sign ?watermark t buf) +let make_pk pk = + Client_keys.make_pk_uri + (Uri.make ~scheme ~path:(Signature.Public_key.to_b58check pk) ()) + +let neuterize sk_uri = + secret_key sk_uri >>=? fun sk -> + return (make_pk (Signature.Secret_key.to_public_key sk)) + +let public_key_hash pk_uri = + public_key pk_uri >>=? fun pk -> + return (Signature.Public_key.hash pk) + +let sign ?watermark sk_uri buf = + secret_key sk_uri >>=? fun sk -> + return (Signature.sign ?watermark sk buf) diff --git a/src/lib_signer_backends/unencrypted.mli b/src/lib_signer_backends/unencrypted.mli index ab4fbe3b2..df90218e3 100644 --- a/src/lib_signer_backends/unencrypted.mli +++ b/src/lib_signer_backends/unencrypted.mli @@ -8,3 +8,6 @@ (**************************************************************************) include Client_keys.SIGNER + +val make_pk: Signature.public_key -> Client_keys.pk_uri +val make_sk: Signature.secret_key -> Client_keys.sk_uri diff --git a/src/proto_alpha/lib_baking/client_baking_endorsement.ml b/src/proto_alpha/lib_baking/client_baking_endorsement.ml index 268f06ab1..1e4fe876e 100644 --- a/src/proto_alpha/lib_baking/client_baking_endorsement.ml +++ b/src/proto_alpha/lib_baking/client_baking_endorsement.ml @@ -103,7 +103,7 @@ let inject_endorsement (cctxt : #Proto_alpha.full) ~slots () >>=? fun bytes -> Client_keys.append - cctxt src_sk ~watermark:Endorsement bytes >>=? fun signed_bytes -> + src_sk ~watermark:Endorsement bytes >>=? fun signed_bytes -> Shell_services.inject_operation cctxt ?async ~chain_id:bi.chain_id signed_bytes >>=? fun oph -> iter_s diff --git a/src/proto_alpha/lib_baking/client_baking_forge.ml b/src/proto_alpha/lib_baking/client_baking_forge.ml index 8cc56ac30..a202c2e85 100644 --- a/src/proto_alpha/lib_baking/client_baking_forge.ml +++ b/src/proto_alpha/lib_baking/client_baking_forge.ml @@ -31,8 +31,7 @@ let forge_block_header { priority ; seed_nonce_hash ; proof_of_work_nonce } in if Baking.check_header_proof_of_work_stamp shell protocol_data stamp_threshold then let unsigned_header = Block_header.forge_unsigned shell protocol_data in - Client_keys.append cctxt - delegate_sk ~watermark:Block_header unsigned_header + Client_keys.append delegate_sk ~watermark:Block_header unsigned_header else loop () in loop () diff --git a/src/proto_alpha/lib_baking/test/proto_alpha_helpers.ml b/src/proto_alpha/lib_baking/test/proto_alpha_helpers.ml index fa59bed2c..c31471106 100644 --- a/src/proto_alpha/lib_baking/test/proto_alpha_helpers.ml +++ b/src/proto_alpha/lib_baking/test/proto_alpha_helpers.ml @@ -114,9 +114,10 @@ let vote_protocol_parameters = let activate_alpha ?(vote = false) () = let fitness = Fitness_repr.from_int64 0L in - let dictator_sk = Client_keys.Secret_key_locator.create - ~scheme:"unencrypted" - ~location:["edsk31vznjHSSpGExDMHYASz45VZqXN4DPxvsa4hAyY8dHM28cZzp6"] in + let dictator_sk = + Tezos_signer_backends.Unencrypted.make_sk + (Signature.Secret_key.of_b58check_exn + "edsk31vznjHSSpGExDMHYASz45VZqXN4DPxvsa4hAyY8dHM28cZzp6") in let protocol_parameters = if vote then vote_protocol_parameters else protocol_parameters in Tezos_client_genesis.Client_proto_main.bake @@ -248,9 +249,8 @@ module Account = struct ~(account:t) ~destination ~amount () = - let src_sk = Client_keys.Secret_key_locator.create - ~scheme:"unencrypted" - ~location:[Signature.Secret_key.to_b58check account.sk] in + let src_sk = + Tezos_signer_backends.Unencrypted.make_sk account.sk in Client_proto_context.transfer (new wrap_full (no_write_context !rpc_config ~block)) block @@ -272,9 +272,8 @@ module Account = struct let delegatable, delegate = match delegate with | None -> false, None | Some delegate -> true, Some delegate in - let src_sk = Client_keys.Secret_key_locator.create - ~scheme:"unencrypted" - ~location:[Signature.Secret_key.to_b58check src.sk] in + let src_sk = + Tezos_signer_backends.Unencrypted.make_sk src.sk in Client_proto_context.originate_account ~source:src.contract ~src_pk:src.pk @@ -506,9 +505,8 @@ module Baking = struct Some (Nonce.hash seed_nonce) else None in - let src_sk = Client_keys.Secret_key_locator.create - ~scheme:"unencrypted" - ~location:[Signature.Secret_key.to_b58check contract.sk] in + let src_sk = + Tezos_signer_backends.Unencrypted.make_sk contract.sk in Client_baking_forge.forge_block ctxt block diff --git a/src/proto_alpha/lib_baking/test/proto_alpha_helpers.mli b/src/proto_alpha/lib_baking/test/proto_alpha_helpers.mli index e0e5b3dd3..46944ba01 100644 --- a/src/proto_alpha/lib_baking/test/proto_alpha_helpers.mli +++ b/src/proto_alpha/lib_baking/test/proto_alpha_helpers.mli @@ -84,7 +84,7 @@ module Account : sig ?block:Block_services.block -> ?fee: Tez.t -> contract:Contract.t -> - manager_sk:Client_keys.Secret_key_locator.t -> + manager_sk:Client_keys.sk_uri -> src_pk:public_key -> public_key_hash option -> Operation_hash.t tzresult Lwt.t diff --git a/src/proto_alpha/lib_client/client_proto_context.ml b/src/proto_alpha/lib_client/client_proto_context.ml index dad81bafc..eca048878 100644 --- a/src/proto_alpha/lib_client/client_proto_context.ml +++ b/src/proto_alpha/lib_client/client_proto_context.ml @@ -55,7 +55,7 @@ let transfer cctxt ~destination ?parameters ~fee () >>=? fun bytes -> Block_services.predecessor cctxt block >>=? fun predecessor -> Client_keys.sign - cctxt src_sk ~watermark:Generic_operation bytes >>=? fun signature -> + src_sk ~watermark:Generic_operation bytes >>=? fun signature -> let signed_bytes = Signature.concat bytes signature in let oph = Operation_hash.hash_bytes [ signed_bytes ] in Alpha_services.Helpers.apply_operation cctxt block @@ -74,7 +74,7 @@ let reveal cctxt cctxt block ~branch ~source ~sourcePubKey:src_pk ~counter ~fee () >>=? fun bytes -> Client_keys.sign - cctxt src_sk ~watermark:Generic_operation bytes >>=? fun signature -> + src_sk ~watermark:Generic_operation bytes >>=? fun signature -> let signed_bytes = Signature.concat bytes signature in let oph = Operation_hash.hash_bytes [ signed_bytes ] in Shell_services.inject_operation @@ -123,7 +123,7 @@ let originate_account ?branch ~counter ~balance ~spendable:true ?delegatable ?delegatePubKey:delegate ~fee () >>=? fun bytes -> Client_keys.sign - cctxt src_sk ~watermark:Generic_operation bytes >>=? fun signature -> + src_sk ~watermark:Generic_operation bytes >>=? fun signature -> originate cctxt ~block ~chain_id ~signature bytes let delegate_contract cctxt @@ -138,7 +138,7 @@ let delegate_contract cctxt ~branch ~source ?sourcePubKey:src_pk ~counter ~fee delegate_opt >>=? fun bytes -> Client_keys.sign - cctxt manager_sk ~watermark:Generic_operation bytes >>=? fun signature -> + manager_sk ~watermark:Generic_operation bytes >>=? fun signature -> let signed_bytes = Signature.concat bytes signature in let oph = Operation_hash.hash_bytes [ signed_bytes ] in Shell_services.inject_operation @@ -241,7 +241,7 @@ let originate_contract ~delegatable ?delegatePubKey:delegate ~script:{ code ; storage } ~fee () >>=? fun bytes -> Client_keys.sign - cctxt src_sk ~watermark:Generic_operation bytes >>=? fun signature -> + src_sk ~watermark:Generic_operation bytes >>=? fun signature -> originate cctxt ~block ~signature bytes let wait_for_operation_inclusion @@ -345,15 +345,17 @@ let claim_commitment (cctxt : #Proto_alpha.full) Shell_services.inject_operation cctxt ~chain_id:bi.chain_id bytes >>=? fun oph -> operation_submitted_message cctxt oph >>=? fun () -> + let pk_uri = Tezos_signer_backends.Unencrypted.make_pk pk in + let sk_uri = Tezos_signer_backends.Unencrypted.make_sk sk in begin match confirmations with | None -> - Client_keys.register_key cctxt ?force (pkh, pk, sk) name >>=? fun () -> + Client_keys.register_key cctxt ?force (pkh, pk_uri, sk_uri) name >>=? fun () -> return () | Some confirmations -> cctxt#message "Waiting for the operation to be included..." >>= fun () -> wait_for_operation_inclusion ~confirmations cctxt oph >>=? fun () -> - Client_keys.register_key cctxt ?force (pkh, pk, sk) name >>=? fun () -> + Client_keys.register_key cctxt ?force (pkh, pk_uri, sk_uri) name >>=? fun () -> Alpha_services.Contract.balance cctxt (`Head 0) (Contract.implicit_contract pkh) >>=? fun balance -> cctxt#message "Account %s (%a) created with %s%a." diff --git a/src/proto_alpha/lib_client/client_proto_programs.ml b/src/proto_alpha/lib_client/client_proto_programs.ml index aca778df0..bc0563ffe 100644 --- a/src/proto_alpha/lib_client/client_proto_programs.ml +++ b/src/proto_alpha/lib_client/client_proto_programs.ml @@ -119,7 +119,7 @@ let trace let hash_and_sign (data : Michelson_v1_parser.parsed) (typ : Michelson_v1_parser.parsed) sk block cctxt = Alpha_services.Helpers.hash_data cctxt block (data.expanded, typ.expanded) >>=? fun hash -> - Client_keys.sign cctxt sk (MBytes.of_string hash) >>=? fun signature -> + Client_keys.sign sk (MBytes.of_string hash) >>=? fun signature -> let `Hex signature = Signature.to_hex signature in return (hash, signature) diff --git a/src/proto_alpha/lib_client/jbuild b/src/proto_alpha/lib_client/jbuild index 789463172..6fb786a54 100644 --- a/src/proto_alpha/lib_client/jbuild +++ b/src/proto_alpha/lib_client/jbuild @@ -9,6 +9,7 @@ tezos-shell-services tezos-client-base tezos-rpc + tezos-signer-backends bip39)) (library_flags (:standard -linkall)) (flags (:standard -w -9+27-30-32-40@8 diff --git a/src/proto_genesis/lib_client/client_proto_main.ml b/src/proto_genesis/lib_client/client_proto_main.ml index 8fe661343..971aa14f2 100644 --- a/src/proto_genesis/lib_client/client_proto_main.ml +++ b/src/proto_genesis/lib_client/client_proto_main.ml @@ -21,7 +21,7 @@ let bake cctxt ?(timestamp = Time.now ()) block command sk = let blk = Data_encoding.Binary.to_bytes_exn Block_header.encoding { shell = shell_header ; protocol_data } in - Client_keys.append cctxt sk blk >>=? fun signed_blk -> + Client_keys.append sk blk >>=? fun signed_blk -> Shell_services.inject_block cctxt signed_blk [] let int64_parameter =