Signer: explicit registration of signers

instead of toplevel side-effects and `-link-all`
This commit is contained in:
Grégoire Henry 2018-05-26 12:37:19 +02:00
parent 502017c863
commit 0dbe24290f
10 changed files with 266 additions and 236 deletions

View File

@ -74,6 +74,12 @@ let main select_commands =
ignore Clic.(setup_formatter Format.err_formatter ignore Clic.(setup_formatter Format.err_formatter
(if Unix.isatty Unix.stderr then Ansi else Plain) Short) ; (if Unix.isatty Unix.stderr then Ansi else Plain) Short) ;
init_logger () >>= fun () -> init_logger () >>= fun () ->
Client_keys.register_signer
(module Tezos_signer_backends.Unencrypted) ;
Client_keys.register_signer
(module Tezos_signer_backends.Encrypted) ;
Client_keys.register_signer
(module Tezos_signer_backends.Remote) ;
Lwt.catch begin fun () -> begin Lwt.catch begin fun () -> begin
Client_config.parse_config_args Client_config.parse_config_args
(new unix_full (new unix_full

View File

@ -8,6 +8,7 @@
tezos-client-commands tezos-client-commands
tezos-stdlib-unix tezos-stdlib-unix
tezos-rpc-http tezos-rpc-http
tezos-signer-backends
pbkdf pbkdf
bip39 bip39
tezos-shell-services)) tezos-shell-services))

View File

@ -9,13 +9,12 @@
open Client_keys open Client_keys
module Encrypted_signer : SIGNER = struct let scheme = "encrypted"
let scheme = "encrypted"
let title = let title =
"Built-in signer using encrypted keys." "Built-in signer using encrypted keys."
let description = let description =
"If you try to import a secret key without additional argument, you will \ "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 \ be asked to either generate a new key, or to import the elements \
from your fundraiser paper wallet.\n\ from your fundraiser paper wallet.\n\
@ -24,26 +23,26 @@ module Encrypted_signer : SIGNER = struct
The format for importing public keys is the raw Base58-encoded \ The format for importing public keys is the raw Base58-encoded \
key (starting with 'edpk')." key (starting with 'edpk')."
type secret_key = Signature.Secret_key.t type secret_key = Signature.Secret_key.t
type public_key = Signature.Public_key.t type public_key = Signature.Public_key.t
(* https://tools.ietf.org/html/rfc2898#section-4.1 *) (* https://tools.ietf.org/html/rfc2898#section-4.1 *)
let salt_len = 8 let salt_len = 8
(* Fixed zero nonce *) (* Fixed zero nonce *)
let nonce = Crypto_box.zero_nonce let nonce = Crypto_box.zero_nonce
(* skloc -> Signature.Secret_key.t *) (* skloc -> Signature.Secret_key.t *)
let decrypted_sks = Hashtbl.create 13 let decrypted_sks = Hashtbl.create 13
let pbkdf ~salt ~password = let pbkdf ~salt ~password =
let open Cstruct in let open Cstruct in
let salt = of_bigarray salt in let salt = of_bigarray salt in
let password = of_bigarray password in let password = of_bigarray password in
to_bigarray to_bigarray
(Pbkdf.pbkdf2 ~prf:`SHA512 ~count:2048 ~dk_len:32l ~salt ~password) (Pbkdf.pbkdf2 ~prf:`SHA512 ~count:2048 ~dk_len:32l ~salt ~password)
let rec decrypt_sk sk salt = function let rec decrypt_sk sk salt = function
| [] -> None | [] -> None
| password :: pws -> | password :: pws ->
let key = Crypto_box.Secretbox.unsafe_of_bytes (pbkdf ~password ~salt) in let key = Crypto_box.Secretbox.unsafe_of_bytes (pbkdf ~password ~salt) in
@ -51,7 +50,7 @@ module Encrypted_signer : SIGNER = struct
| None -> decrypt_sk sk salt pws | None -> decrypt_sk sk salt pws
| Some sk -> Some sk | Some sk -> Some sk
let salt_skenc_of_skloc skloc = let salt_skenc_of_skloc skloc =
let open Cstruct in let open Cstruct in
let skloc = of_string skloc in let skloc = of_string skloc in
let len = len skloc in let len = len skloc in
@ -59,7 +58,7 @@ module Encrypted_signer : SIGNER = struct
let skenc = sub skloc salt_len (len - salt_len) in let skenc = sub skloc salt_len (len - salt_len) in
to_bigarray salt, to_bigarray skenc to_bigarray salt, to_bigarray skenc
let rec passwd_ask_loop (cctxt : #Client_context.io_wallet) ~name ~salt ~skenc = 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 -> cctxt#prompt_password "Enter password for encrypted key %s: " name >>=? fun password ->
let key = pbkdf ~salt ~password in let key = pbkdf ~salt ~password in
let key = Crypto_box.Secretbox.unsafe_of_bytes key in let key = Crypto_box.Secretbox.unsafe_of_bytes key in
@ -70,7 +69,7 @@ module Encrypted_signer : SIGNER = struct
Signature.Secret_key.encoding Signature.Secret_key.encoding
decrypted_sk)) decrypted_sk))
let ask_all_passwords (cctxt : #Client_context.io_wallet) sks = let ask_all_passwords (cctxt : #Client_context.io_wallet) sks =
fold_left_s begin fun a (name, skloc) -> fold_left_s begin fun a (name, skloc) ->
if Secret_key_locator.scheme skloc <> scheme then if Secret_key_locator.scheme skloc <> scheme then
return a return a
@ -95,21 +94,21 @@ module Encrypted_signer : SIGNER = struct
|_ -> Lwt.fail Exit |_ -> Lwt.fail Exit
end [] sks end [] sks
let init cctxt = let init cctxt =
Secret_key.load cctxt >>=? fun sks -> Secret_key.load cctxt >>=? fun sks ->
Lwt.try_bind Lwt.try_bind
(fun () -> ask_all_passwords cctxt sks) (fun () -> ask_all_passwords cctxt sks)
(fun _ -> return ()) (fun _ -> return ())
(fun _ -> failwith "Corrupted secret key database. Aborting.") (fun _ -> failwith "Corrupted secret key database. Aborting.")
let input_new_passphrase (cctxt : #Client_context.io_wallet) = let input_new_passphrase (cctxt : #Client_context.io_wallet) =
cctxt#prompt_password "Enter passphrase to encrypt your key: " >>=? fun password -> cctxt#prompt_password "Enter passphrase to encrypt your key: " >>=? fun password ->
cctxt#prompt_password "Confirm passphrase: " >>=? fun confirm -> cctxt#prompt_password "Confirm passphrase: " >>=? fun confirm ->
if password <> confirm then if password <> confirm then
failwith "Passphrases do not match." failwith "Passphrases do not match."
else return password else return password
let encrypt_sk cctxt sk = let encrypt_sk cctxt sk =
input_new_passphrase cctxt >>=? fun password -> input_new_passphrase cctxt >>=? fun password ->
let salt = Rand.generate salt_len in let salt = Rand.generate salt_len in
let key = Crypto_box.Secretbox.unsafe_of_bytes (pbkdf ~password ~salt) in let key = Crypto_box.Secretbox.unsafe_of_bytes (pbkdf ~password ~salt) in
@ -120,7 +119,7 @@ module Encrypted_signer : SIGNER = struct
Hashtbl.replace decrypted_sks location sk ; Hashtbl.replace decrypted_sks location sk ;
return (Secret_key_locator.create ~scheme ~location:[location]) return (Secret_key_locator.create ~scheme ~location:[location])
let rec get_boolean_answer (cctxt : #Client_context.io_wallet) ~default ~msg = 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 let prompt = if default then "(Y/n/q)" else "(y/N/q)" in
cctxt#prompt "%s %s: " msg prompt >>=? fun gen -> cctxt#prompt "%s %s: " msg prompt >>=? fun gen ->
match default, String.lowercase_ascii gen with match default, String.lowercase_ascii gen with
@ -130,7 +129,7 @@ module Encrypted_signer : SIGNER = struct
| _, "q" -> failwith "Exit by user request." | _, "q" -> failwith "Exit by user request."
| _ -> get_boolean_answer cctxt ~msg ~default | _ -> get_boolean_answer cctxt ~msg ~default
let rec sk_of_mnemonic (cctxt : #Client_context.io_wallet) = let rec sk_of_mnemonic (cctxt : #Client_context.io_wallet) =
cctxt#prompt "Enter the e-mail used for the paper wallet: " >>=? fun email -> cctxt#prompt "Enter the e-mail used for the paper wallet: " >>=? fun email ->
let rec loop_words acc i = let rec loop_words acc i =
if i > 14 then return (List.rev acc) else if i > 14 then return (List.rev acc) else
@ -159,7 +158,7 @@ module Encrypted_signer : SIGNER = struct
| true -> return sk | true -> return sk
| false -> sk_of_mnemonic cctxt | false -> sk_of_mnemonic cctxt
let sk_locator_of_human_input cctxt = function let sk_locator_of_human_input cctxt = function
| sk :: _ -> | sk :: _ ->
Lwt.return (Signature.Secret_key.of_b58check sk) >>=? fun sk -> Lwt.return (Signature.Secret_key.of_b58check sk) >>=? fun sk ->
encrypt_sk cctxt sk encrypt_sk cctxt sk
@ -178,11 +177,11 @@ module Encrypted_signer : SIGNER = struct
encrypt_sk cctxt sk encrypt_sk cctxt sk
end end
let pk_locator_of_human_input _cctxt = function let pk_locator_of_human_input _cctxt = function
| [] -> failwith "Missing public key argument." | [] -> 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 = function let sk_of_locator = function
| (Sk_locator { location = [location] }) -> begin | (Sk_locator { location = [location] }) -> begin
match Hashtbl.find decrypted_sks location with match Hashtbl.find decrypted_sks location with
| exception Not_found -> failwith "Unknown secret key location." | exception Not_found -> failwith "Unknown secret key location."
@ -191,27 +190,23 @@ module Encrypted_signer : SIGNER = struct
| (Sk_locator { location = _ }) -> | (Sk_locator { location = _ }) ->
failwith "Wrong location type." failwith "Wrong location type."
let pk_of_locator = function let pk_of_locator = function
|(Pk_locator { location = [location] }) -> |(Pk_locator { location = [location] }) ->
Lwt.return (Signature.Public_key.of_b58check location) Lwt.return (Signature.Public_key.of_b58check location)
|(Pk_locator { location = _ }) -> |(Pk_locator { location = _ }) ->
failwith "Wrong location type." failwith "Wrong location type."
let sk_to_locator sk = let sk_to_locator sk =
Secret_key_locator.create Secret_key_locator.create
~scheme ~location:[Signature.Secret_key.to_b58check sk] |> ~scheme ~location:[Signature.Secret_key.to_b58check sk] |>
Lwt.return Lwt.return
let pk_to_locator pk = let pk_to_locator pk =
Public_key_locator.create Public_key_locator.create
~scheme ~location:[Signature.Public_key.to_b58check pk] |> ~scheme ~location:[Signature.Public_key.to_b58check pk] |>
Lwt.return Lwt.return
let neuterize x = Lwt.return (Signature.Secret_key.to_public_key x) let neuterize x = Lwt.return (Signature.Secret_key.to_public_key x)
let public_key x = return x let public_key x = return x
let public_key_hash x = return (Signature.Public_key.hash x) let public_key_hash x = return (Signature.Public_key.hash x)
let sign ?watermark t buf = return (Signature.sign ?watermark t buf) let sign ?watermark t buf = return (Signature.sign ?watermark t buf)
end
let () =
register_signer (module Encrypted_signer)

View File

@ -0,0 +1,10 @@
(**************************************************************************)
(* *)
(* Copyright (c) 2014 - 2017. *)
(* Dynamic Ledger Solutions, Inc. <contact@tezos.com> *)
(* *)
(* All rights reserved. No warranty, explicit or implicit, provided. *)
(* *)
(**************************************************************************)
include Client_keys.SIGNER

View File

@ -15,7 +15,7 @@
-open Tezos_client_base -open Tezos_client_base
-open Tezos_signer_services -open Tezos_signer_services
-open Tezos_rpc_http -open Tezos_rpc_http
-linkall -w -9)))) -w -9))))
(alias (alias
((name runtest_indent) ((name runtest_indent)

View File

@ -166,5 +166,4 @@ module Remote_signer : SIGNER = struct
end end
let () = include Remote_signer
register_signer (module Remote_signer)

View File

@ -0,0 +1,10 @@
(**************************************************************************)
(* *)
(* Copyright (c) 2014 - 2017. *)
(* Dynamic Ledger Solutions, Inc. <contact@tezos.com> *)
(* *)
(* All rights reserved. No warranty, explicit or implicit, provided. *)
(* *)
(**************************************************************************)
include Client_keys.SIGNER

View File

@ -9,13 +9,12 @@
open Client_keys open Client_keys
module Unencrypted_signer : SIGNER = struct let scheme = "unencrypted"
let scheme = "unencrypted"
let title = let title =
"Built-in signer using raw unencrypted keys." "Built-in signer using raw unencrypted keys."
let description = let description =
"Do not use this signer except for playing on the test chain.\n\ "Do not use this signer except for playing on the test chain.\n\
The format for importing secret keys is either no argument (will \ The format for importing secret keys is either no argument (will \
generate a key) or the raw Base58-encoded key (starting with \ generate a key) or the raw Base58-encoded key (starting with \
@ -23,12 +22,12 @@ module Unencrypted_signer : SIGNER = struct
The format for importing public keys is the raw Base58-encoded \ The format for importing public keys is the raw Base58-encoded \
key (starting with 'edpk')." key (starting with 'edpk')."
type secret_key = Signature.Secret_key.t type secret_key = Signature.Secret_key.t
type public_key = Signature.Public_key.t type public_key = Signature.Public_key.t
let init _wallet = return () let init _wallet = return ()
let sk_locator_of_human_input _cctxt = function let sk_locator_of_human_input _cctxt = function
| sk :: _ -> | sk :: _ ->
return (Secret_key_locator.create ~scheme ~location:[sk]) return (Secret_key_locator.create ~scheme ~location:[sk])
| [] -> | [] ->
@ -36,38 +35,34 @@ module Unencrypted_signer : SIGNER = struct
return (Secret_key_locator.create ~scheme 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 let pk_locator_of_human_input _cctxt = function
| [] -> failwith "Missing public key argument" | [] -> 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 = function let sk_of_locator = function
|(Sk_locator { location = ( location :: _ ) }) -> |(Sk_locator { location = ( location :: _ ) }) ->
Lwt.return (Signature.Secret_key.of_b58check location) Lwt.return (Signature.Secret_key.of_b58check location)
|(Sk_locator { location = _ }) -> |(Sk_locator { location = _ }) ->
failwith "Wrong type of location" failwith "Wrong type of location"
let pk_of_locator = function let pk_of_locator = function
|(Pk_locator { location = ( location :: _ ) }) -> |(Pk_locator { location = ( location :: _ ) }) ->
Lwt.return (Signature.Public_key.of_b58check location) Lwt.return (Signature.Public_key.of_b58check location)
|(Pk_locator { location = _ }) -> |(Pk_locator { location = _ }) ->
failwith "Wrong type of location" failwith "Wrong type of location"
let sk_to_locator sk = let sk_to_locator sk =
Secret_key_locator.create Secret_key_locator.create
~scheme ~location:[Signature.Secret_key.to_b58check sk] |> ~scheme ~location:[Signature.Secret_key.to_b58check sk] |>
Lwt.return Lwt.return
let pk_to_locator pk = let pk_to_locator pk =
Public_key_locator.create Public_key_locator.create
~scheme ~location:[Signature.Public_key.to_b58check pk] |> ~scheme ~location:[Signature.Public_key.to_b58check pk] |>
Lwt.return Lwt.return
let neuterize x = Lwt.return (Signature.Secret_key.to_public_key x) let neuterize x = Lwt.return (Signature.Secret_key.to_public_key x)
let public_key x = return x let public_key x = return x
let public_key_hash x = return (Signature.Public_key.hash x) let public_key_hash x = return (Signature.Public_key.hash x)
let sign ?watermark t buf = return (Signature.sign ?watermark t buf) let sign ?watermark t buf = return (Signature.sign ?watermark t buf)
end
let () =
register_signer (module Unencrypted_signer)

View File

@ -0,0 +1,10 @@
(**************************************************************************)
(* *)
(* Copyright (c) 2014 - 2017. *)
(* Dynamic Ledger Solutions, Inc. <contact@tezos.com> *)
(* *)
(* All rights reserved. No warranty, explicit or implicit, provided. *)
(* *)
(**************************************************************************)
include Client_keys.SIGNER

View File

@ -616,3 +616,7 @@ let display_level block =
let endorsement_security_deposit block = let endorsement_security_deposit block =
Constants_services.endorsement_security_deposit !rpc_ctxt block Constants_services.endorsement_security_deposit !rpc_ctxt block
let () =
Client_keys.register_signer
(module Tezos_signer_backends.Unencrypted)