From 8b9d02eec40785fbffcea15f9d22f32d7455d140 Mon Sep 17 00:00:00 2001 From: Pietro Date: Thu, 12 Apr 2018 17:57:08 +0200 Subject: [PATCH] Client, wallet: Change type of location --- src/lib_client_base/client_keys.ml | 73 +++++++++++++------ src/lib_client_base/client_keys.mli | 15 ++-- .../client_signer_encrypted.ml | 64 +++++++++------- .../client_signer_unencrypted.ml | 29 +++++--- .../client_keys_commands.ml | 6 +- .../lib_baking/test/proto_alpha_helpers.ml | 8 +- 6 files changed, 122 insertions(+), 73 deletions(-) diff --git a/src/lib_client_base/client_keys.ml b/src/lib_client_base/client_keys.ml index 93954e3b0..31e55484f 100644 --- a/src/lib_client_base/client_keys.ml +++ b/src/lib_client_base/client_keys.ml @@ -8,6 +8,7 @@ (**************************************************************************) type error += Unregistered_key_scheme of string + let () = register_error_kind `Permanent ~id: "cli.unregistered_key_scheme" @@ -29,19 +30,21 @@ 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:string -> t + val create : scheme:string -> location:location -> t val scheme : t -> string - val location : t -> string + val location : t -> location val to_string : t -> string val pp : Format.formatter -> t -> unit end -type sk_locator = Sk_locator of { scheme : string ; location : string } -type pk_locator = Pk_locator of { scheme : string ; location : string } +type sk_locator = Sk_locator of { scheme : string ; location : location } +type pk_locator = Pk_locator of { scheme : string ; location : location } module Sk_locator = struct let name = "secret key" @@ -54,10 +57,10 @@ module Sk_locator = struct let location (Sk_locator { location }) = location let to_string (Sk_locator { scheme ; location }) = - scheme ^ ":" ^ location + String.concat "/" ((scheme ^ ":") :: List.map Uri.pct_encode location) - let pp ppf (Sk_locator { scheme ; location }) = - Format.pp_print_string ppf (scheme ^ ":" ^ location) + let pp ppf loc = + Format.pp_print_string ppf (to_string loc) end module Pk_locator = struct @@ -71,10 +74,10 @@ module Pk_locator = struct let location (Pk_locator { location }) = location let to_string (Pk_locator { scheme ; location }) = - scheme ^ ":" ^ location + String.concat "/" ((scheme ^ ":") :: List.map Uri.pct_encode location) - let pp ppf (Pk_locator { scheme ; location }) = - Format.pp_print_string ppf (scheme ^ ":" ^ location) + let pp ppf loc = + Format.pp_print_string ppf (to_string loc) end module type KEY = sig @@ -88,7 +91,7 @@ module Locator (K : KEY) (L : LOCATOR) = struct let of_unencrypted k = L.create ~scheme:"unencrypted" - ~location:(K.to_b58check k) + ~location:[K.to_b58check k] let of_string s = match String.index s ':' with @@ -96,9 +99,13 @@ module Locator (K : KEY) (L : LOCATOR) = struct of_unencrypted (K.of_b58check_exn s) | i -> let len = String.length s in - create - ~scheme:(String.sub s 0 i) - ~location:(String.sub s (i+1) (len-i-1)) + 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) @@ -125,8 +132,8 @@ module type SIGNER = sig val sk_to_locator : secret_key -> sk_locator Lwt.t val pk_to_locator : public_key -> pk_locator Lwt.t val neuterize : secret_key -> public_key Lwt.t - val public_key : public_key -> Signature.Public_key.t Lwt.t - val public_key_hash : public_key -> Signature.Public_key_hash.t 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 sign : ?watermark: Signature.watermark -> secret_key -> MBytes.t -> Signature.t tzresult Lwt.t @@ -140,7 +147,8 @@ let register_signer signer = let find_signer_for_key cctxt ~scheme = match Hashtbl.find signers_table scheme with - | exception Not_found -> fail (Unregistered_key_scheme scheme) + | exception Not_found -> + fail (Unregistered_key_scheme scheme) | signer, false -> let module Signer = (val signer : SIGNER) in Signer.init cctxt >>=? fun () -> @@ -151,11 +159,33 @@ let find_signer_for_key cctxt ~scheme = let registered_signers () : (string * (module SIGNER)) list = Hashtbl.fold (fun k (v, _) acc -> (k, v) :: acc) signers_table [] +type error += Signature_mismatch of Secret_key_locator.t + +let () = + register_error_kind `Permanent + ~id: "cli.signature_mismatch" + ~title: "Signature mismatch" + ~description: "The signer produced an invalid signature" + ~pp: + (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)) + (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 module Signer = (val signer : SIGNER) in Signer.sk_of_locator skloc >>=? fun t -> - Signer.sign ?watermark t buf + Signer.sign ?watermark t buf >>=? fun signature -> + Signer.neuterize t >>= fun pk -> + Signer.public_key pk >>=? fun pubkey -> + fail_unless + (Signature.check pubkey signature buf) + (Signature_mismatch skloc) >>=? fun () -> + return signature let append ?watermark cctxt loc buf = sign ?watermark cctxt loc buf >>|? fun signature -> @@ -241,7 +271,7 @@ let get_key (cctxt : #Client_context.wallet) pkh = 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 -> + Signer.public_key pk >>=? fun pk -> return (n, pk, sk) let get_keys (wallet : #Client_context.io_wallet) = @@ -254,7 +284,7 @@ let get_keys (wallet : #Client_context.io_wallet) = 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 -> + Signer.public_key pk >>=? fun pk -> return (name, pkh, pk, sk) end >>= function | Ok r -> Lwt.return (Some r) @@ -277,10 +307,11 @@ let alias_keys cctxt name = | [] -> return None | (key_name, pkh) :: tl -> if key_name = name - then + 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 diff --git a/src/lib_client_base/client_keys.mli b/src/lib_client_base/client_keys.mli index 9647ba638..197fbfa73 100644 --- a/src/lib_client_base/client_keys.mli +++ b/src/lib_client_base/client_keys.mli @@ -9,16 +9,17 @@ (** {2 Location of keys using schemes} *) -type sk_locator = Sk_locator of { scheme : string ; location : string } -type pk_locator = Pk_locator of { scheme : string ; location : string } +type location = string list +type sk_locator = Sk_locator of { scheme : string ; location : location } +type pk_locator = Pk_locator of { scheme : string ; location : location } module type LOCATOR = sig val name : string type t - val create : scheme:string -> location:string -> t + val create : scheme:string -> location:location -> t val scheme : t -> string - val location : t -> string + val location : t -> location val to_string : t -> string val pp : Format.formatter -> t -> unit end @@ -84,10 +85,10 @@ module type SIGNER = sig val neuterize : secret_key -> public_key Lwt.t (** [neuterize sk] is the corresponding [pk]. *) - val public_key : public_key -> Signature.Public_key.t Lwt.t - (** [public_key pk] is the full version of [pk]. *) + val public_key : public_key -> 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 Lwt.t + val public_key_hash : public_key -> Signature.Public_key_hash.t tzresult Lwt.t (** [public_key_hash pk] is the hash of [pk]. *) val sign : diff --git a/src/lib_client_base_unix/client_signer_encrypted.ml b/src/lib_client_base_unix/client_signer_encrypted.ml index 35d7a19aa..9d3ebccbb 100644 --- a/src/lib_client_base_unix/client_signer_encrypted.ml +++ b/src/lib_client_base_unix/client_signer_encrypted.ml @@ -76,21 +76,24 @@ module Encrypted_signer : SIGNER = struct if Secret_key_locator.scheme skloc <> scheme then Lwt.return a else - let location = Secret_key_locator.location skloc in - 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) ; - Lwt.return a - | None -> - passwd_ask_loop - cctxt ~name ~salt ~skenc >>= fun (passwd, decrypted_sk) -> - Hashtbl.replace decrypted_sks location decrypted_sk ; - Lwt.return (passwd :: a) + 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); + Lwt.return a + | None -> + passwd_ask_loop + cctxt ~name ~salt ~skenc >>= fun (passwd, decrypted_sk) -> + Hashtbl.replace decrypted_sks location decrypted_sk ; + Lwt.return (passwd :: a) + end + |_ -> Lwt.fail Exit end [] sks let init cctxt = @@ -117,7 +120,7 @@ module Encrypted_signer : SIGNER = struct 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) + return (Secret_key_locator.create ~scheme ~location:[location]) 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 @@ -179,29 +182,36 @@ module Encrypted_signer : SIGNER = struct let pk_locator_of_human_input _cctxt = function | [] -> failwith "Missing public key argument." - | pk :: _ -> return (Public_key_locator.create ~scheme ~location:pk) + | pk :: _ -> return (Public_key_locator.create ~scheme ~location:[pk]) - let sk_of_locator (Sk_locator { location }) = - match Hashtbl.find decrypted_sks location with - | exception Not_found -> failwith "Unknown secret key location." - | sk -> return sk + 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 (Pk_locator { location }) = - Lwt.return (Signature.Public_key.of_b58check location) + let pk_of_locator = function + |(Pk_locator { location = [location] }) -> + Lwt.return (Signature.Public_key.of_b58check location) + |(Pk_locator { location = _ }) -> + failwith "Wrong location type." let sk_to_locator sk = Secret_key_locator.create - ~scheme ~location:(Signature.Secret_key.to_b58check sk) |> + ~scheme ~location:[Signature.Secret_key.to_b58check sk] |> Lwt.return let pk_to_locator pk = Public_key_locator.create - ~scheme ~location:(Signature.Public_key.to_b58check pk) |> + ~scheme ~location:[Signature.Public_key.to_b58check pk] |> Lwt.return let neuterize x = Lwt.return (Signature.Secret_key.to_public_key x) - let public_key x = Lwt.return x - let public_key_hash x = Lwt.return (Signature.Public_key.hash 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) end diff --git a/src/lib_client_base_unix/client_signer_unencrypted.ml b/src/lib_client_base_unix/client_signer_unencrypted.ml index aa46246a4..3adfcafd4 100644 --- a/src/lib_client_base_unix/client_signer_unencrypted.ml +++ b/src/lib_client_base_unix/client_signer_unencrypted.ml @@ -30,35 +30,42 @@ module Unencrypted_signer : SIGNER = struct let sk_locator_of_human_input _cctxt = function | sk :: _ -> - return (Secret_key_locator.create ~scheme ~location:sk) + return (Secret_key_locator.create ~scheme ~location:[sk]) | [] -> let _, _, sk = Ed25519.generate_key () in return (Secret_key_locator.create ~scheme - ~location:(Ed25519.Secret_key.to_b58check sk)) + ~location:[Ed25519.Secret_key.to_b58check sk]) let pk_locator_of_human_input _cctxt = function | [] -> failwith "Missing public key argument" - | pk :: _ -> return (Public_key_locator.create ~scheme ~location:pk) + | pk :: _ -> return (Public_key_locator.create ~scheme ~location:[pk]) - let sk_of_locator (Sk_locator { location }) = - Lwt.return (Signature.Secret_key.of_b58check location) + 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 (Pk_locator { location }) = - Lwt.return (Signature.Public_key.of_b58check 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) |> + ~scheme ~location:[Signature.Secret_key.to_b58check sk] |> Lwt.return let pk_to_locator pk = Public_key_locator.create - ~scheme ~location:(Signature.Public_key.to_b58check pk) |> + ~scheme ~location:[Signature.Public_key.to_b58check pk] |> Lwt.return let neuterize x = Lwt.return (Signature.Secret_key.to_public_key x) - let public_key x = Lwt.return x - let public_key_hash x = Lwt.return (Signature.Public_key.hash 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) end diff --git a/src/lib_client_commands/client_keys_commands.ml b/src/lib_client_commands/client_keys_commands.ml index 3f94f1e95..353c29ad6 100644 --- a/src/lib_client_commands/client_keys_commands.ml +++ b/src/lib_client_commands/client_keys_commands.ml @@ -107,7 +107,7 @@ let commands () = Signer.pk_to_locator pk >>= fun pkloc -> Public_key.find_opt cctxt name >>=? function | None -> - Signer.public_key_hash pk >>= fun pkh -> + 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 @@ -142,7 +142,7 @@ let commands () = 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 -> + Signer.public_key_hash pk >>=? fun pkh -> Public_key_hash.add ~force cctxt name pkh >>=? fun () -> Public_key.add ~force cctxt name pkloc) ; @@ -192,7 +192,7 @@ let commands () = 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 -> + Signer.public_key pk >>=? fun pk -> ok_lwt @@ cctxt#message "Public Key: %a" Signature.Public_key.pp pk >>=? fun () -> if show_private then 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 7d64ddf06..00feb6cc9 100644 --- a/src/proto_alpha/lib_baking/test/proto_alpha_helpers.ml +++ b/src/proto_alpha/lib_baking/test/proto_alpha_helpers.ml @@ -116,7 +116,7 @@ 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 + ~location:["edsk31vznjHSSpGExDMHYASz45VZqXN4DPxvsa4hAyY8dHM28cZzp6"] in let protocol_parameters = if vote then vote_protocol_parameters else protocol_parameters in Tezos_client_genesis.Client_proto_main.bake @@ -250,7 +250,7 @@ module Account = struct ~amount () = let src_sk = Client_keys.Secret_key_locator.create ~scheme:"unencrypted" - ~location:(Signature.Secret_key.to_b58check account.sk) in + ~location:[Signature.Secret_key.to_b58check account.sk] in Client_proto_context.transfer (new wrap_full (no_write_context !rpc_config ~block)) block @@ -274,7 +274,7 @@ module Account = struct | 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 + ~location:[Signature.Secret_key.to_b58check src.sk] in Client_proto_context.originate_account ~source:src.contract ~src_pk:src.pk @@ -508,7 +508,7 @@ module Baking = struct None in let src_sk = Client_keys.Secret_key_locator.create ~scheme:"unencrypted" - ~location:(Signature.Secret_key.to_b58check contract.sk) in + ~location:[Signature.Secret_key.to_b58check contract.sk] in Client_baking_forge.forge_block ctxt block