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://`.
This commit is contained in:
parent
80dd9ebf24
commit
f69d4a5186
@ -190,35 +190,35 @@ log_endorser() {
|
|||||||
|
|
||||||
BOOTSTRAP1_IDENTITY="tz1KqTpEZ7Yob7QbPE4Hy4Wo8fHG8LhKxZSx"
|
BOOTSTRAP1_IDENTITY="tz1KqTpEZ7Yob7QbPE4Hy4Wo8fHG8LhKxZSx"
|
||||||
BOOTSTRAP1_PUBLIC="edpkuBknW28nW72KG6RoHtYW7p12T6GKc7nAbwYX5m8Wd9sDVC9yav"
|
BOOTSTRAP1_PUBLIC="edpkuBknW28nW72KG6RoHtYW7p12T6GKc7nAbwYX5m8Wd9sDVC9yav"
|
||||||
BOOTSTRAP1_SECRET="edsk3gUfUPyBSfrS9CCgmCiQsTCHGkviBDusMxDJstFtojtc1zcpsh"
|
BOOTSTRAP1_SECRET="unencrypted:edsk3gUfUPyBSfrS9CCgmCiQsTCHGkviBDusMxDJstFtojtc1zcpsh"
|
||||||
|
|
||||||
BOOTSTRAP2_IDENTITY="tz1gjaF81ZRRvdzjobyfVNsAeSC6PScjfQwN"
|
BOOTSTRAP2_IDENTITY="tz1gjaF81ZRRvdzjobyfVNsAeSC6PScjfQwN"
|
||||||
BOOTSTRAP2_PUBLIC="edpktzNbDAUjUk697W7gYg2CRuBQjyPxbEg8dLccYYwKSKvkPvjtV9"
|
BOOTSTRAP2_PUBLIC="edpktzNbDAUjUk697W7gYg2CRuBQjyPxbEg8dLccYYwKSKvkPvjtV9"
|
||||||
BOOTSTRAP2_SECRET="edsk39qAm1fiMjgmPkw1EgQYkMzkJezLNewd7PLNHTkr6w9XA2zdfo"
|
BOOTSTRAP2_SECRET="unencrypted:edsk39qAm1fiMjgmPkw1EgQYkMzkJezLNewd7PLNHTkr6w9XA2zdfo"
|
||||||
|
|
||||||
BOOTSTRAP3_IDENTITY="tz1faswCTDciRzE4oJ9jn2Vm2dvjeyA9fUzU"
|
BOOTSTRAP3_IDENTITY="tz1faswCTDciRzE4oJ9jn2Vm2dvjeyA9fUzU"
|
||||||
BOOTSTRAP3_PUBLIC="edpkuTXkJDGcFd5nh6VvMz8phXxU3Bi7h6hqgywNFi1vZTfQNnS1RV"
|
BOOTSTRAP3_PUBLIC="edpkuTXkJDGcFd5nh6VvMz8phXxU3Bi7h6hqgywNFi1vZTfQNnS1RV"
|
||||||
BOOTSTRAP3_SECRET="edsk4ArLQgBTLWG5FJmnGnT689VKoqhXwmDPBuGx3z4cvwU9MmrPZZ"
|
BOOTSTRAP3_SECRET="unencrypted:edsk4ArLQgBTLWG5FJmnGnT689VKoqhXwmDPBuGx3z4cvwU9MmrPZZ"
|
||||||
|
|
||||||
BOOTSTRAP4_IDENTITY="tz1b7tUupMgCNw2cCLpKTkSD1NZzB5TkP2sv"
|
BOOTSTRAP4_IDENTITY="tz1b7tUupMgCNw2cCLpKTkSD1NZzB5TkP2sv"
|
||||||
BOOTSTRAP4_PUBLIC="edpkuFrRoDSEbJYgxRtLx2ps82UdaYc1WwfS9sE11yhauZt5DgCHbU"
|
BOOTSTRAP4_PUBLIC="edpkuFrRoDSEbJYgxRtLx2ps82UdaYc1WwfS9sE11yhauZt5DgCHbU"
|
||||||
BOOTSTRAP4_SECRET="edsk2uqQB9AY4FvioK2YMdfmyMrer5R8mGFyuaLLFfSRo8EoyNdht3"
|
BOOTSTRAP4_SECRET="unencrypted:edsk2uqQB9AY4FvioK2YMdfmyMrer5R8mGFyuaLLFfSRo8EoyNdht3"
|
||||||
|
|
||||||
BOOTSTRAP5_IDENTITY="tz1ddb9NMYHZi5UzPdzTZMYQQZoMub195zgv"
|
BOOTSTRAP5_IDENTITY="tz1ddb9NMYHZi5UzPdzTZMYQQZoMub195zgv"
|
||||||
BOOTSTRAP5_PUBLIC="edpkv8EUUH68jmo3f7Um5PezmfGrRF24gnfLpH3sVNwJnV5bVCxL2n"
|
BOOTSTRAP5_PUBLIC="edpkv8EUUH68jmo3f7Um5PezmfGrRF24gnfLpH3sVNwJnV5bVCxL2n"
|
||||||
BOOTSTRAP5_SECRET="edsk4QLrcijEffxV31gGdN2HU7UpyJjA8drFoNcmnB28n89YjPNRFm"
|
BOOTSTRAP5_SECRET="unencrypted:edsk4QLrcijEffxV31gGdN2HU7UpyJjA8drFoNcmnB28n89YjPNRFm"
|
||||||
|
|
||||||
DICTATOR_SECRET="edsk31vznjHSSpGExDMHYASz45VZqXN4DPxvsa4hAyY8dHM28cZzp6"
|
DICTATOR_SECRET="unencrypted:edsk31vznjHSSpGExDMHYASz45VZqXN4DPxvsa4hAyY8dHM28cZzp6"
|
||||||
|
|
||||||
add_sandboxed_bootstrap_identities() {
|
add_sandboxed_bootstrap_identities() {
|
||||||
|
|
||||||
${client} import unencrypted secret key bootstrap1 ${BOOTSTRAP1_SECRET}
|
${client} import secret key bootstrap1 ${BOOTSTRAP1_SECRET}
|
||||||
${client} import unencrypted secret key bootstrap2 ${BOOTSTRAP2_SECRET}
|
${client} import secret key bootstrap2 ${BOOTSTRAP2_SECRET}
|
||||||
${client} import unencrypted secret key bootstrap3 ${BOOTSTRAP3_SECRET}
|
${client} import secret key bootstrap3 ${BOOTSTRAP3_SECRET}
|
||||||
${client} import unencrypted secret key bootstrap4 ${BOOTSTRAP4_SECRET}
|
${client} import secret key bootstrap4 ${BOOTSTRAP4_SECRET}
|
||||||
${client} import unencrypted secret key bootstrap5 ${BOOTSTRAP5_SECRET}
|
${client} import secret key bootstrap5 ${BOOTSTRAP5_SECRET}
|
||||||
|
|
||||||
${client} import unencrypted secret key dictator ${DICTATOR_SECRET}
|
${client} import secret key dictator ${DICTATOR_SECRET}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -16,7 +16,7 @@ let sign (cctxt : #Client_context.wallet) pkh data =
|
|||||||
(MBytes.get_uint8 data 0) >>= fun () ->
|
(MBytes.get_uint8 data 0) >>= fun () ->
|
||||||
Client_keys.get_key cctxt pkh >>=? fun (name, _pkh, sk_uri) ->
|
Client_keys.get_key cctxt pkh >>=? fun (name, _pkh, sk_uri) ->
|
||||||
log "Signing data for key %s" name >>= fun () ->
|
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
|
return signature
|
||||||
|
|
||||||
let public_key (cctxt : #Client_context.wallet) pkh =
|
let public_key (cctxt : #Client_context.wallet) pkh =
|
||||||
|
@ -163,7 +163,9 @@ let main () =
|
|||||||
inherit Client_context_unix.unix_wallet ~base_dir
|
inherit Client_context_unix.unix_wallet ~base_dir
|
||||||
end in
|
end in
|
||||||
Client_keys.register_signer
|
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
|
Client_keys.register_signer
|
||||||
(module Tezos_signer_backends.Unencrypted) ;
|
(module Tezos_signer_backends.Unencrypted) ;
|
||||||
let commands =
|
let commands =
|
||||||
|
@ -30,136 +30,63 @@ module Public_key_hash = Client_aliases.Alias (struct
|
|||||||
let name = "public key hash"
|
let name = "public key hash"
|
||||||
end)
|
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
|
module type KEY = sig
|
||||||
type t
|
type t
|
||||||
val to_b58check : t -> string
|
val to_b58check : t -> string
|
||||||
val of_b58check_exn : string -> t
|
val of_b58check_exn : string -> t
|
||||||
end
|
end
|
||||||
|
|
||||||
module Locator (K : KEY) (L : LOCATOR) = struct
|
let uri_encoding =
|
||||||
include L
|
Data_encoding.(conv Uri.to_string Uri.of_string string)
|
||||||
|
|
||||||
let of_unencrypted k =
|
module Entity (Name : sig val name: string end) = struct
|
||||||
L.create ~scheme:"unencrypted"
|
include Name
|
||||||
~location:[K.to_b58check k]
|
type t = Uri.t
|
||||||
|
let pp = Uri.pp_hum
|
||||||
let of_string s =
|
let of_source s = return (Uri.of_string s)
|
||||||
match String.index s ':' with
|
let to_source t = return (Uri.to_string t)
|
||||||
| exception Not_found ->
|
let encoding = uri_encoding
|
||||||
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)
|
|
||||||
end
|
end
|
||||||
|
|
||||||
module Secret_key_locator = Locator(Signature.Secret_key)(Sk_locator)
|
type pk_uri = Uri.t
|
||||||
module Secret_key = Client_aliases.Alias (Secret_key_locator)
|
let make_pk_uri x = x
|
||||||
module Public_key_locator = Locator(Signature.Public_key)(Pk_locator)
|
|
||||||
module Public_key = Client_aliases.Alias (Public_key_locator)
|
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
|
module type SIGNER = sig
|
||||||
type secret_key
|
|
||||||
type public_key
|
|
||||||
val scheme : string
|
val scheme : string
|
||||||
val title : string
|
val title : string
|
||||||
val description : string
|
val description : string
|
||||||
val init : #Client_context.io_wallet -> unit tzresult Lwt.t
|
val neuterize : sk_uri -> pk_uri tzresult Lwt.t
|
||||||
val sk_locator_of_human_input : #Client_context.io_wallet -> string list -> sk_uri tzresult Lwt.t
|
val public_key : pk_uri -> Signature.Public_key.t tzresult Lwt.t
|
||||||
val pk_locator_of_human_input : #Client_context.io_wallet -> string list -> pk_uri tzresult Lwt.t
|
val public_key_hash : pk_uri -> Signature.Public_key_hash.t 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 sign :
|
val sign :
|
||||||
?watermark: Signature.watermark ->
|
?watermark: Signature.watermark ->
|
||||||
secret_key -> MBytes.t -> Signature.t tzresult Lwt.t
|
sk_uri -> MBytes.t -> Signature.t tzresult Lwt.t
|
||||||
end
|
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 register_signer signer =
|
||||||
let module Signer = (val signer : SIGNER) in
|
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
|
match Hashtbl.find signers_table scheme with
|
||||||
| exception Not_found ->
|
| exception Not_found ->
|
||||||
fail (Unregistered_key_scheme scheme)
|
fail (Unregistered_key_scheme scheme)
|
||||||
| signer, false ->
|
| signer -> return signer
|
||||||
let module Signer = (val signer : SIGNER) in
|
|
||||||
Signer.init cctxt >>=? fun () ->
|
|
||||||
Hashtbl.replace signers_table scheme (signer, true) ;
|
|
||||||
return signer
|
|
||||||
| signer, true -> return signer
|
|
||||||
|
|
||||||
let registered_signers () : (string * (module SIGNER)) list =
|
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 () =
|
let () =
|
||||||
register_error_kind `Permanent
|
register_error_kind `Permanent
|
||||||
@ -170,134 +97,87 @@ let () =
|
|||||||
(fun ppf sk ->
|
(fun ppf sk ->
|
||||||
Format.fprintf ppf
|
Format.fprintf ppf
|
||||||
"The signer for %a produced an invalid signature"
|
"The signer for %a produced an invalid signature"
|
||||||
Secret_key_locator.pp sk)
|
Uri.pp_hum sk)
|
||||||
Data_encoding.(obj1 (req "locator" Secret_key_locator.encoding))
|
Data_encoding.(obj1 (req "locator" uri_encoding))
|
||||||
(function Signature_mismatch sk -> Some sk | _ -> None)
|
(function Signature_mismatch sk -> Some sk | _ -> None)
|
||||||
(fun sk -> Signature_mismatch sk)
|
(fun sk -> Signature_mismatch sk)
|
||||||
|
|
||||||
let sign ?watermark cctxt ((Sk_locator { scheme }) as skloc) buf =
|
let neuterize sk_uri =
|
||||||
find_signer_for_key cctxt ~scheme >>=? fun signer ->
|
let scheme = Option.unopt ~default:"" (Uri.scheme sk_uri) in
|
||||||
|
find_signer_for_key ~scheme >>=? fun signer ->
|
||||||
let module Signer = (val signer : SIGNER) in
|
let module Signer = (val signer : SIGNER) in
|
||||||
Signer.sk_of_locator skloc >>=? fun t ->
|
Signer.neuterize sk_uri
|
||||||
Signer.sign ?watermark t buf >>=? fun signature ->
|
|
||||||
Signer.neuterize t >>= fun pk ->
|
let public_key pk_uri =
|
||||||
Signer.public_key pk >>=? fun pubkey ->
|
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
|
fail_unless
|
||||||
(Signature.check ?watermark pubkey signature buf)
|
(Signature.check ?watermark pubkey signature buf)
|
||||||
(Signature_mismatch skloc) >>=? fun () ->
|
(Signature_mismatch sk_uri) >>=? fun () ->
|
||||||
return signature
|
return signature
|
||||||
|
|
||||||
let append ?watermark cctxt loc buf =
|
let append ?watermark loc buf =
|
||||||
sign ?watermark cctxt loc buf >>|? fun signature ->
|
sign ?watermark loc buf >>|? fun signature ->
|
||||||
Signature.concat buf signature
|
Signature.concat buf signature
|
||||||
|
|
||||||
let register_key cctxt ?(force=false)
|
let register_key cctxt ?(force=false) (public_key_hash, pk_uri, sk_uri) name =
|
||||||
(public_key_hash, public_key, secret_key) name =
|
Public_key.add ~force cctxt name pk_uri >>=? fun () ->
|
||||||
Secret_key.add ~force cctxt name
|
Secret_key.add ~force cctxt name sk_uri >>=? fun () ->
|
||||||
(Secret_key_locator.of_unencrypted secret_key) >>=? fun () ->
|
Public_key_hash.add ~force cctxt name public_key_hash >>=? 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 ()
|
return ()
|
||||||
|
|
||||||
let gen_keys ?(force=false) ?algo ?seed (cctxt : #Client_context.io_wallet) name =
|
let raw_get_key (cctxt : #Client_context.wallet) pkh =
|
||||||
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 =
|
|
||||||
Public_key_hash.rev_find cctxt pkh >>=? function
|
Public_key_hash.rev_find cctxt pkh >>=? function
|
||||||
| None -> failwith "no keys for the source contract manager"
|
| None -> failwith "no keys for the source contract manager"
|
||||||
| Some n ->
|
| Some n ->
|
||||||
Public_key.find cctxt n >>=? fun pk ->
|
Public_key.find_opt cctxt n >>=? fun pk_uri ->
|
||||||
Secret_key.find cctxt n >>=? fun sk ->
|
Secret_key.find_opt cctxt n >>=? fun sk_uri ->
|
||||||
let scheme = Secret_key_locator.scheme sk in
|
begin
|
||||||
find_signer_for_key cctxt ~scheme >>=? fun signer ->
|
Option.unopt_map
|
||||||
let module Signer = (val signer : SIGNER) in
|
~default:Lwt.return_none
|
||||||
Signer.pk_of_locator pk >>=? fun pk ->
|
~f:(fun pkh ->
|
||||||
Signer.public_key pk >>=? fun pk ->
|
public_key pkh >>= function
|
||||||
return (n, pk, sk)
|
| 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 =
|
let get_key cctxt pkh =
|
||||||
Public_key_hash.rev_find cctxt pkh >>=? function
|
raw_get_key cctxt pkh >>=? function
|
||||||
| None -> failwith "no keys for the source contract manager"
|
| (pkh, Some pk, Some sk) -> return (pkh, pk, sk)
|
||||||
| Some n ->
|
| (_pkh, _pk, None) -> failwith "... FIXME ... E"
|
||||||
Public_key.find cctxt n >>=? fun pk ->
|
| (_pkh, None, _sk) -> failwith "... FIXME ... F"
|
||||||
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_keys (wallet : #Client_context.io_wallet) =
|
let get_public_key cctxt pkh =
|
||||||
Secret_key.load wallet >>=? fun sks ->
|
raw_get_key cctxt pkh >>=? function
|
||||||
Lwt_list.filter_map_s begin fun (name, sk) ->
|
| (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
|
begin
|
||||||
Public_key.find wallet name >>=? fun pk ->
|
Public_key.find cctxt name >>=? fun pk_uri ->
|
||||||
Public_key_hash.find wallet name >>=? fun pkh ->
|
Public_key_hash.find cctxt name >>=? fun pkh ->
|
||||||
let scheme = Public_key_locator.scheme pk in
|
public_key pk_uri >>=? fun pk ->
|
||||||
find_signer_for_key wallet ~scheme >>=? fun signer ->
|
return (name, pkh, pk, sk_uri)
|
||||||
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)
|
|
||||||
end >>= function
|
end >>= function
|
||||||
| Ok r -> Lwt.return (Some r)
|
| Ok r -> Lwt.return (Some r)
|
||||||
| Error _ -> Lwt.return_none
|
| Error _ -> Lwt.return_none
|
||||||
@ -308,24 +188,18 @@ let list_keys cctxt =
|
|||||||
Public_key_hash.load cctxt >>=? fun l ->
|
Public_key_hash.load cctxt >>=? fun l ->
|
||||||
map_s
|
map_s
|
||||||
(fun (name, pkh) ->
|
(fun (name, pkh) ->
|
||||||
Public_key.find_opt cctxt name >>=? fun pkm ->
|
raw_get_key cctxt pkh >>= function
|
||||||
Secret_key.find_opt cctxt name >>=? fun pks ->
|
| Ok (_name, pk, sk_uri) ->
|
||||||
return (name, pkh, pkm, pks))
|
return (name, pkh, pk, sk_uri)
|
||||||
|
| Error _ ->
|
||||||
|
return (name, pkh, None, None))
|
||||||
l
|
l
|
||||||
|
|
||||||
let alias_keys cctxt name =
|
let alias_keys cctxt name =
|
||||||
Public_key_hash.load cctxt >>=? fun l ->
|
Public_key_hash.find cctxt name >>=? fun pkh ->
|
||||||
let rec find_key = function
|
raw_get_key cctxt pkh >>= function
|
||||||
| [] -> return None
|
| Ok (_name, pk, sk_uri) -> return (Some (pkh, pk, sk_uri))
|
||||||
| (key_name, pkh) :: tl ->
|
| Error _ -> return None
|
||||||
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
|
|
||||||
|
|
||||||
let force_switch () =
|
let force_switch () =
|
||||||
Clic.switch
|
Clic.switch
|
||||||
|
@ -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 } *)
|
(** {2 Cryptographic keys tables } *)
|
||||||
|
|
||||||
|
type pk_uri = private Uri.t
|
||||||
|
type sk_uri = private Uri.t
|
||||||
|
|
||||||
module Public_key_hash :
|
module Public_key_hash :
|
||||||
Client_aliases.Alias with type t = Signature.Public_key_hash.t
|
Client_aliases.Alias with type t = Signature.Public_key_hash.t
|
||||||
module Public_key :
|
module Public_key :
|
||||||
@ -39,8 +22,6 @@ module Secret_key :
|
|||||||
(** {2 Interface for external signing modules.} *)
|
(** {2 Interface for external signing modules.} *)
|
||||||
|
|
||||||
module type SIGNER = sig
|
module type SIGNER = sig
|
||||||
type secret_key
|
|
||||||
type public_key
|
|
||||||
|
|
||||||
val scheme : string
|
val scheme : string
|
||||||
(** [scheme] is the name of the scheme implemented by this signer
|
(** [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
|
(** [description] is a multi-line human readable description of the
|
||||||
signer, that should include the format of key specifications. *)
|
signer, that should include the format of key specifications. *)
|
||||||
|
|
||||||
val init :
|
val neuterize : sk_uri -> pk_uri tzresult Lwt.t
|
||||||
#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
|
|
||||||
(** [neuterize sk] is the corresponding [pk]. *)
|
(** [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]. *)
|
(** [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]. *)
|
(** [public_key_hash pk] is the hash of [pk]. *)
|
||||||
|
|
||||||
val sign :
|
val sign :
|
||||||
?watermark: Signature.watermark ->
|
?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
|
(** [sign ?watermark sk data] is signature obtained by signing [data] with
|
||||||
[sk]. *)
|
[sk]. *)
|
||||||
end
|
end
|
||||||
@ -104,59 +56,51 @@ val register_signer : (module SIGNER) -> unit
|
|||||||
|
|
||||||
val registered_signers : unit -> (string * (module SIGNER)) list
|
val registered_signers : unit -> (string * (module SIGNER)) list
|
||||||
|
|
||||||
val find_signer_for_key :
|
val public_key : pk_uri -> Signature.Public_key.t tzresult Lwt.t
|
||||||
#Client_context.io_wallet -> scheme:string -> (module SIGNER) 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 :
|
val sign :
|
||||||
?watermark:Signature.watermark ->
|
?watermark:Signature.watermark ->
|
||||||
#Client_context.io_wallet ->
|
|
||||||
sk_uri -> MBytes.t -> Signature.t tzresult Lwt.t
|
sk_uri -> MBytes.t -> Signature.t tzresult Lwt.t
|
||||||
|
|
||||||
val append :
|
val append :
|
||||||
?watermark:Signature.watermark ->
|
?watermark:Signature.watermark ->
|
||||||
#Client_context.io_wallet ->
|
|
||||||
sk_uri -> MBytes.t -> MBytes.t tzresult Lwt.t
|
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 :
|
val register_key :
|
||||||
#Client_context.wallet ->
|
#Client_context.wallet ->
|
||||||
?force:bool ->
|
?force:bool ->
|
||||||
(Signature.Public_key_hash.t *
|
(Signature.Public_key_hash.t * pk_uri * sk_uri) -> string -> unit tzresult Lwt.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
|
|
||||||
|
|
||||||
val list_keys :
|
val list_keys :
|
||||||
#Client_context.wallet ->
|
#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 :
|
val alias_keys :
|
||||||
#Client_context.wallet -> string ->
|
#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:
|
val get_key :
|
||||||
#Client_context.io_wallet ->
|
#Client_context.wallet ->
|
||||||
Public_key_hash.t ->
|
Public_key_hash.t ->
|
||||||
(string * Signature.Public_key.t * sk_uri) tzresult Lwt.t
|
(string * Signature.Public_key.t * sk_uri) tzresult Lwt.t
|
||||||
|
|
||||||
val get_public_key:
|
val get_public_key :
|
||||||
#Client_context.io_wallet ->
|
#Client_context.wallet ->
|
||||||
Public_key_hash.t ->
|
Public_key_hash.t ->
|
||||||
(string * Signature.Public_key.t) tzresult Lwt.t
|
(string * Signature.Public_key.t) tzresult Lwt.t
|
||||||
|
|
||||||
val get_keys:
|
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
|
(string * Public_key_hash.t * Signature.Public_key.t * sk_uri) list tzresult Lwt.t
|
||||||
|
|
||||||
val force_switch : unit -> (bool, 'ctx) Clic.arg
|
val force_switch : unit -> (bool, 'ctx) Clic.arg
|
||||||
|
|
||||||
|
(**/**)
|
||||||
|
|
||||||
|
val make_pk_uri : Uri.t -> pk_uri
|
||||||
|
val make_sk_uri : Uri.t -> sk_uri
|
||||||
|
|
||||||
|
@ -77,9 +77,15 @@ let main select_commands =
|
|||||||
Client_keys.register_signer
|
Client_keys.register_signer
|
||||||
(module Tezos_signer_backends.Unencrypted) ;
|
(module Tezos_signer_backends.Unencrypted) ;
|
||||||
Client_keys.register_signer
|
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
|
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
|
Lwt.catch begin fun () -> begin
|
||||||
Client_config.parse_config_args
|
Client_config.parse_config_args
|
||||||
(new unix_full
|
(new unix_full
|
||||||
|
@ -22,7 +22,64 @@ let sig_algo_arg =
|
|||||||
~default: "ed25519"
|
~default: "ed25519"
|
||||||
(Signature.algo_param ())
|
(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 open Clic in
|
||||||
let show_private_switch =
|
let show_private_switch =
|
||||||
switch
|
switch
|
||||||
@ -61,7 +118,10 @@ let commands () =
|
|||||||
@@ stop)
|
@@ stop)
|
||||||
(fun (force, algo) name (cctxt : #Client_context.io_wallet) ->
|
(fun (force, algo) name (cctxt : #Client_context.io_wallet) ->
|
||||||
Secret_key.of_fresh cctxt force name >>=? fun name ->
|
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."
|
command ~group ~desc: "Generate (unencrypted) keys including the given string."
|
||||||
(args2
|
(args2
|
||||||
@ -82,69 +142,53 @@ let commands () =
|
|||||||
command ~group ~desc: "Add a secret key to the wallet."
|
command ~group ~desc: "Add a secret key to the wallet."
|
||||||
(args1 (Secret_key.force_switch ()))
|
(args1 (Secret_key.force_switch ()))
|
||||||
(prefix "import"
|
(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" ]
|
@@ prefixes [ "secret" ; "key" ]
|
||||||
@@ Secret_key.fresh_alias_param
|
@@ Secret_key.fresh_alias_param
|
||||||
@@ seq_of_param
|
@@ param
|
||||||
(string
|
~name:"uri"
|
||||||
~name:"spec"
|
~desc:"secret key\n\
|
||||||
~desc:"secret key specification\n\
|
Varies from one scheme to the other.\n\
|
||||||
Varies from one scheme to the other.\n\
|
Use command `list signing schemes` for more \
|
||||||
Use command `list signing schemes` for more \
|
information."
|
||||||
information."))
|
(parameter (fun _ s ->
|
||||||
(fun force scheme name spec cctxt ->
|
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 ->
|
Secret_key.of_fresh cctxt force name >>=? fun name ->
|
||||||
find_signer_for_key ~scheme cctxt >>=? fun signer ->
|
Client_keys.neuterize sk_uri >>=? fun pk_uri ->
|
||||||
let module Signer = (val signer : SIGNER) in
|
begin
|
||||||
Signer.sk_locator_of_human_input
|
Public_key.find_opt cctxt name >>=? function
|
||||||
(cctxt :> Client_context.io_wallet) spec >>=? fun skloc ->
|
| None -> return ()
|
||||||
Signer.sk_of_locator skloc >>=? fun sk ->
|
| Some pk ->
|
||||||
Signer.neuterize sk >>= fun pk ->
|
fail_unless (pk_uri = pk || force)
|
||||||
Signer.pk_to_locator pk >>= fun pkloc ->
|
(failure
|
||||||
Public_key.find_opt cctxt name >>=? function
|
"public and secret keys '%s' don't correspond, \
|
||||||
| None ->
|
please don't use -force" name)
|
||||||
Signer.public_key_hash pk >>=? fun pkh ->
|
end >>=? fun () ->
|
||||||
Secret_key.add ~force cctxt name skloc >>=? fun () ->
|
Client_keys.public_key_hash pk_uri >>=? fun pkh ->
|
||||||
Public_key_hash.add ~force cctxt name pkh >>=? fun () ->
|
register_key cctxt ~force (pkh, pk_uri, sk_uri) name) ;
|
||||||
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) ;
|
|
||||||
|
|
||||||
command ~group ~desc: "Add a public key to the wallet."
|
command ~group ~desc: "Add a public key to the wallet."
|
||||||
(args1 (Public_key.force_switch ()))
|
(args1 (Public_key.force_switch ()))
|
||||||
(prefix "import"
|
(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" ]
|
@@ prefixes [ "public" ; "key" ]
|
||||||
@@ Public_key.fresh_alias_param
|
@@ Public_key.fresh_alias_param
|
||||||
@@ seq_of_param
|
@@ param
|
||||||
(string
|
~name:"uri"
|
||||||
~name:"spec"
|
~desc:"public key\n\
|
||||||
~desc:"public key specification\n\
|
Varies from one scheme to the other.\n\
|
||||||
Varies from one scheme to the other.\n\
|
Use command `list signing schemes` for more \
|
||||||
Use command `list signing schemes` for more \
|
information."
|
||||||
information."))
|
(parameter (fun _ s ->
|
||||||
(fun force scheme name location cctxt ->
|
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 ->
|
Public_key.of_fresh cctxt force name >>=? fun name ->
|
||||||
find_signer_for_key ~scheme cctxt >>=? fun signer ->
|
Client_keys.public_key_hash pk_uri >>=? fun pkh ->
|
||||||
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 ->
|
|
||||||
Public_key_hash.add ~force cctxt name pkh >>=? fun () ->
|
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."
|
command ~group ~desc: "Add an identity to the wallet."
|
||||||
(args1 (Public_key.force_switch ()))
|
(args1 (Public_key.force_switch ()))
|
||||||
@ -166,10 +210,13 @@ let commands () =
|
|||||||
begin match pk, sk with
|
begin match pk, sk with
|
||||||
| None, None ->
|
| None, None ->
|
||||||
cctxt#message "%s: %s" name v
|
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
|
cctxt#message "%s: %s (%s sk known)" name v scheme
|
||||||
| Some Pk_locator { scheme }, _ ->
|
| Some _, _ ->
|
||||||
cctxt#message "%s: %s (%s pk known)" name v scheme
|
cctxt#message "%s: %s (pk known)" name v
|
||||||
end >>= fun () -> return ()
|
end >>= fun () -> return ()
|
||||||
end l) ;
|
end l) ;
|
||||||
|
|
||||||
@ -179,36 +226,35 @@ let commands () =
|
|||||||
@@ Public_key_hash.alias_param
|
@@ Public_key_hash.alias_param
|
||||||
@@ stop)
|
@@ stop)
|
||||||
(fun show_private (name, _) (cctxt : #Client_context.io_wallet) ->
|
(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 ->
|
alias_keys cctxt name >>=? fun key_info ->
|
||||||
match key_info with
|
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) ->
|
| Some (pkh, pk, skloc) ->
|
||||||
ok_lwt @@ cctxt#message "Hash: %a"
|
cctxt#message "Hash: %a"
|
||||||
Signature.Public_key_hash.pp pkh >>=? fun () ->
|
Signature.Public_key_hash.pp pkh >>= fun () ->
|
||||||
match pk with
|
match pk with
|
||||||
| None -> return ()
|
| None -> return ()
|
||||||
| Some (Pk_locator { scheme } as pkloc) ->
|
| Some pk ->
|
||||||
find_signer_for_key ~scheme cctxt >>=? fun signer ->
|
cctxt#message "Public Key: %a"
|
||||||
let module Signer = (val signer : SIGNER) in
|
Signature.Public_key.pp pk >>= fun () ->
|
||||||
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 () ->
|
|
||||||
if show_private then
|
if show_private then
|
||||||
match skloc with
|
match skloc with
|
||||||
| None -> return ()
|
| None -> return ()
|
||||||
| Some skloc ->
|
| Some skloc ->
|
||||||
Secret_key.to_source skloc >>=? fun skloc ->
|
Secret_key.to_source skloc >>=? fun skloc ->
|
||||||
ok_lwt @@ cctxt#message "Secret Key: %s" skloc
|
cctxt#message "Secret Key: %s" skloc >>= fun () ->
|
||||||
else return ()) ;
|
return ()
|
||||||
|
else
|
||||||
|
return ()) ;
|
||||||
|
|
||||||
command ~group ~desc: "Forget the entire wallet of keys."
|
command ~group ~desc: "Forget the entire wallet of keys."
|
||||||
(args1 (Clic.switch
|
(args1 (Clic.switch
|
||||||
~long:"force" ~short:'f'
|
~long:"force" ~short:'f'
|
||||||
~doc:"you got to use the force for that" ()))
|
~doc:"you got to use the force for that" ()))
|
||||||
(fixed [ "forget" ; "all" ; "keys" ])
|
(fixed [ "forget" ; "all" ; "keys" ])
|
||||||
(fun force cctxt ->
|
(fun force (cctxt : Client_context.io_wallet) ->
|
||||||
fail_unless force
|
fail_unless force
|
||||||
(failure "this can only used with option -force") >>=? fun () ->
|
(failure "this can only used with option -force") >>=? fun () ->
|
||||||
Public_key.set cctxt [] >>=? fun () ->
|
Public_key.set cctxt [] >>=? fun () ->
|
||||||
|
@ -6,7 +6,8 @@
|
|||||||
(libraries (tezos-base
|
(libraries (tezos-base
|
||||||
tezos-client-base
|
tezos-client-base
|
||||||
tezos-rpc
|
tezos-rpc
|
||||||
tezos-shell-services))
|
tezos-shell-services
|
||||||
|
tezos-signer-backends))
|
||||||
(library_flags (:standard -linkall))
|
(library_flags (:standard -linkall))
|
||||||
(flags (:standard -w -9+27-30-32-40@8
|
(flags (:standard -w -9+27-30-32-40@8
|
||||||
-safe-string
|
-safe-string
|
||||||
|
@ -11,153 +11,156 @@ open Client_keys
|
|||||||
|
|
||||||
let scheme = "encrypted"
|
let scheme = "encrypted"
|
||||||
|
|
||||||
let title =
|
module Raw = struct
|
||||||
"Built-in signer using encrypted keys."
|
|
||||||
|
|
||||||
let description =
|
(* https://tools.ietf.org/html/rfc2898#section-4.1 *)
|
||||||
"If you try to import a secret key without additional argument, you will \
|
let salt_len = 8
|
||||||
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')."
|
|
||||||
|
|
||||||
type secret_key = Signature.Secret_key.t
|
(* Fixed zero nonce *)
|
||||||
type public_key = Signature.Public_key.t
|
let nonce = Crypto_box.zero_nonce
|
||||||
|
|
||||||
(* https://tools.ietf.org/html/rfc2898#section-4.1 *)
|
let pbkdf ~salt ~password =
|
||||||
let salt_len = 8
|
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 encrypt ~password sk =
|
||||||
let nonce = Crypto_box.zero_nonce
|
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 decrypt ~password ~encrypted_sk =
|
||||||
let decrypted_sks = Hashtbl.create 13
|
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 =
|
end
|
||||||
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)
|
|
||||||
|
|
||||||
let rec decrypt_sk sk salt = function
|
let decrypted = Hashtbl.create 13
|
||||||
| [] -> None
|
let passwords = ref []
|
||||||
| 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 salt_skenc_of_skloc skloc =
|
let rec interactive_decrypt_loop
|
||||||
let open Cstruct in
|
(cctxt : #Client_context.prompter)
|
||||||
let skloc = of_string skloc in
|
?name ~encrypted_sk =
|
||||||
let len = len skloc in
|
begin
|
||||||
let salt = sub skloc 0 salt_len in
|
match name with
|
||||||
let skenc = sub skloc salt_len (len - salt_len) in
|
| None ->
|
||||||
to_bigarray salt, to_bigarray skenc
|
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 =
|
let rec noninteractice_decrypt_loop ~encrypted_sk = function
|
||||||
cctxt#prompt_password "Enter password for encrypted key %s: " name >>=? fun password ->
|
| [] -> return None
|
||||||
let key = pbkdf ~salt ~password in
|
| password :: passwords ->
|
||||||
let key = Crypto_box.Secretbox.unsafe_of_bytes key in
|
Raw.decrypt ~password ~encrypted_sk >>=? function
|
||||||
match Crypto_box.Secretbox.box_open key skenc nonce with
|
| None -> noninteractice_decrypt_loop ~encrypted_sk passwords
|
||||||
| None -> passwd_ask_loop cctxt ~name ~salt ~skenc
|
| Some sk -> return (Some sk)
|
||||||
| Some decrypted_sk ->
|
|
||||||
return (password, (Data_encoding.Binary.of_bytes_exn
|
|
||||||
Signature.Secret_key.encoding
|
|
||||||
decrypted_sk))
|
|
||||||
|
|
||||||
let ask_all_passwords (cctxt : #Client_context.io_wallet) sks =
|
let decrypt_payload cctxt ?name encrypted_sk =
|
||||||
fold_left_s begin fun a (name, skloc) ->
|
match Base58.safe_decode encrypted_sk with
|
||||||
if Secret_key_locator.scheme skloc <> scheme then
|
| None -> failwith "... FIXME ... A"
|
||||||
return a
|
| Some encrypted_sk ->
|
||||||
else
|
let encrypted_sk = MBytes.of_string encrypted_sk in
|
||||||
match Secret_key_locator.location skloc with
|
noninteractice_decrypt_loop ~encrypted_sk !passwords >>=? function
|
||||||
|location :: _ -> begin
|
| Some sk -> return sk
|
||||||
match Base58.safe_decode location with
|
| None -> interactive_decrypt_loop cctxt ?name ~encrypted_sk
|
||||||
| 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 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 ->
|
Secret_key.load cctxt >>=? fun sks ->
|
||||||
Lwt.try_bind
|
iter_s begin fun (name, sk_uri) ->
|
||||||
(fun () -> ask_all_passwords cctxt sks)
|
if Uri.scheme (sk_uri : sk_uri :> Uri.t) <> Some scheme then
|
||||||
(fun _ -> return ())
|
return ()
|
||||||
(fun _ -> failwith "Corrupted secret key database. Aborting.")
|
else
|
||||||
|
decrypt cctxt ~name sk_uri >>=? fun _ ->
|
||||||
|
return ()
|
||||||
|
end sks
|
||||||
|
|
||||||
let input_new_passphrase (cctxt : #Client_context.io_wallet) =
|
let rec read_passphrase (cctxt : #Client_context.io) =
|
||||||
cctxt#prompt_password "Enter passphrase to encrypt your key: " >>=? fun password ->
|
cctxt#prompt_password
|
||||||
cctxt#prompt_password "Confirm passphrase: " >>=? fun confirm ->
|
"Enter passphrase to encrypt your key: " >>=? fun password ->
|
||||||
if password <> confirm then
|
cctxt#prompt_password
|
||||||
failwith "Passphrases do not match."
|
"Confirm passphrase: " >>=? fun confirm ->
|
||||||
else return password
|
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 =
|
let encrypt cctxt sk =
|
||||||
input_new_passphrase cctxt >>=? fun password ->
|
read_passphrase cctxt >>=? fun password ->
|
||||||
let salt = Rand.generate salt_len in
|
let payload = Raw.encrypt ~password sk in
|
||||||
let key = Crypto_box.Secretbox.unsafe_of_bytes (pbkdf ~password ~salt) in
|
let path = Base58.safe_encode (MBytes.to_string payload) in
|
||||||
let msg = Data_encoding.Binary.to_bytes_exn Signature.Secret_key.encoding sk in
|
let sk_uri = Client_keys.make_sk_uri (Uri.make ~scheme ~path ()) in
|
||||||
let encrypted_passwd = Crypto_box.Secretbox.box key msg nonce in
|
Hashtbl.replace decrypted sk_uri sk ;
|
||||||
let payload = MBytes.(to_string (concat "" [salt; encrypted_passwd])) in
|
return sk_uri
|
||||||
let location = Base58.safe_encode payload in
|
|
||||||
Hashtbl.replace decrypted_sks location sk ;
|
|
||||||
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
|
|
||||||
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) =
|
let rec get_boolean_answer (cctxt : #Client_context.io_wallet) ~default ~msg =
|
||||||
cctxt#prompt "Enter the e-mail used for the paper wallet: " >>=? fun email ->
|
let prompt = if default then "(Y/n/q)" else "(y/N/q)" in
|
||||||
let rec loop_words acc i =
|
cctxt#prompt "%s %s: " msg prompt >>= fun gen ->
|
||||||
if i > 14 then return (List.rev acc) else
|
match default, String.lowercase_ascii gen with
|
||||||
cctxt#prompt_password "Enter word %d: " i >>=? fun word ->
|
| default, "" -> return default
|
||||||
match Bip39.index_of_word (MBytes.to_string word) with
|
| _, "y" -> return true
|
||||||
| None -> loop_words acc i
|
| _, "n" -> return false
|
||||||
| Some wordidx -> loop_words (wordidx :: acc) (succ i) in
|
| _, "q" -> failwith "Exit by user request."
|
||||||
loop_words [] 0 >>=? fun words ->
|
| _ -> get_boolean_answer cctxt ~msg ~default
|
||||||
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 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
|
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 ->
|
||||||
@ -176,37 +179,38 @@ let sk_locator_of_human_input cctxt = function
|
|||||||
sk_of_mnemonic cctxt >>=? fun sk ->
|
sk_of_mnemonic cctxt >>=? fun sk ->
|
||||||
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
|
|
||||||
| (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
|
module Make(C : sig val cctxt: Client_context.prompter end) = struct
|
||||||
|(Pk_locator { location = [location] }) ->
|
|
||||||
Lwt.return (Signature.Public_key.of_b58check location)
|
|
||||||
|(Pk_locator { location = _ }) ->
|
|
||||||
failwith "Wrong location type."
|
|
||||||
|
|
||||||
let sk_to_locator sk =
|
let scheme = "encrypted"
|
||||||
Secret_key_locator.create
|
|
||||||
~scheme ~location:[Signature.Secret_key.to_b58check sk] |>
|
|
||||||
Lwt.return
|
|
||||||
|
|
||||||
let pk_to_locator pk =
|
let title =
|
||||||
Public_key_locator.create
|
"Built-in signer using encrypted keys."
|
||||||
~scheme ~location:[Signature.Public_key.to_b58check pk] |>
|
|
||||||
Lwt.return
|
|
||||||
|
|
||||||
let neuterize x = Lwt.return (Signature.Secret_key.to_public_key x)
|
let description =
|
||||||
let public_key x = return x
|
"If you try to import a secret key without additional argument, you will \
|
||||||
let public_key_hash x = return (Signature.Public_key.hash x)
|
be asked to either generate a new key, or to import the elements \
|
||||||
let sign ?watermark t buf = return (Signature.sign ?watermark t buf)
|
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
|
||||||
|
@ -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
|
||||||
|
49
src/lib_signer_backends/https.ml
Normal file
49
src/lib_signer_backends/https.ml
Normal file
@ -0,0 +1,49 @@
|
|||||||
|
(**************************************************************************)
|
||||||
|
(* *)
|
||||||
|
(* Copyright (c) 2014 - 2018. *)
|
||||||
|
(* Dynamic Ledger Solutions, Inc. <contact@tezos.com> *)
|
||||||
|
(* *)
|
||||||
|
(* 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
|
@ -1,6 +1,6 @@
|
|||||||
(**************************************************************************)
|
(**************************************************************************)
|
||||||
(* *)
|
(* *)
|
||||||
(* Copyright (c) 2014 - 2017. *)
|
(* Copyright (c) 2014 - 2018. *)
|
||||||
(* Dynamic Ledger Solutions, Inc. <contact@tezos.com> *)
|
(* Dynamic Ledger Solutions, Inc. <contact@tezos.com> *)
|
||||||
(* *)
|
(* *)
|
||||||
(* All rights reserved. No warranty, explicit or implicit, provided. *)
|
(* All rights reserved. No warranty, explicit or implicit, provided. *)
|
@ -14,8 +14,7 @@
|
|||||||
-open Tezos_stdlib_unix
|
-open Tezos_stdlib_unix
|
||||||
-open Tezos_client_base
|
-open Tezos_client_base
|
||||||
-open Tezos_signer_services
|
-open Tezos_signer_services
|
||||||
-open Tezos_rpc_http
|
-open Tezos_rpc_http))))
|
||||||
-w -9))))
|
|
||||||
|
|
||||||
(alias
|
(alias
|
||||||
((name runtest_indent)
|
((name runtest_indent)
|
||||||
|
@ -1,172 +0,0 @@
|
|||||||
(**************************************************************************)
|
|
||||||
(* *)
|
|
||||||
(* Copyright (c) 2014 - 2018. *)
|
|
||||||
(* Dynamic Ledger Solutions, Inc. <contact@tezos.com> *)
|
|
||||||
(* *)
|
|
||||||
(* 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] <remote key alias>\n\
|
|
||||||
\ - tcp [host] [port] <remote key alias>\n\
|
|
||||||
\ - https [host] [port] <remote key alias>\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
|
|
||||||
"@[<v 2>Remote Schema : wrong locator %s.@,@[<hov 0>%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
|
|
105
src/lib_signer_backends/socket.ml
Normal file
105
src/lib_signer_backends/socket.ml
Normal file
@ -0,0 +1,105 @@
|
|||||||
|
(**************************************************************************)
|
||||||
|
(* *)
|
||||||
|
(* Copyright (c) 2014 - 2018. *)
|
||||||
|
(* Dynamic Ledger Solutions, Inc. <contact@tezos.com> *)
|
||||||
|
(* *)
|
||||||
|
(* 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
|
11
src/lib_signer_backends/socket.mli
Normal file
11
src/lib_signer_backends/socket.mli
Normal file
@ -0,0 +1,11 @@
|
|||||||
|
(**************************************************************************)
|
||||||
|
(* *)
|
||||||
|
(* Copyright (c) 2014 - 2018. *)
|
||||||
|
(* Dynamic Ledger Solutions, Inc. <contact@tezos.com> *)
|
||||||
|
(* *)
|
||||||
|
(* All rights reserved. No warranty, explicit or implicit, provided. *)
|
||||||
|
(* *)
|
||||||
|
(**************************************************************************)
|
||||||
|
|
||||||
|
module Unix : Client_keys.SIGNER
|
||||||
|
module Tcp : Client_keys.SIGNER
|
@ -22,11 +22,7 @@ let description =
|
|||||||
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 public_key = Signature.Public_key.t
|
|
||||||
|
|
||||||
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])
|
||||||
@ -39,30 +35,31 @@ 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
|
*)
|
||||||
|(Sk_locator { location = ( location :: _ ) }) ->
|
let secret_key sk_uri =
|
||||||
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] |>
|
|
||||||
Lwt.return
|
Lwt.return
|
||||||
|
(Signature.Secret_key.of_b58check (Uri.path (sk_uri : sk_uri :> Uri.t)))
|
||||||
|
|
||||||
let pk_to_locator pk =
|
let make_sk sk =
|
||||||
Public_key_locator.create
|
Client_keys.make_sk_uri
|
||||||
~scheme ~location:[Signature.Public_key.to_b58check pk] |>
|
(Uri.make ~scheme ~path:(Signature.Secret_key.to_b58check sk) ())
|
||||||
|
|
||||||
|
let public_key pk_uri =
|
||||||
Lwt.return
|
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 make_pk pk =
|
||||||
let public_key x = return x
|
Client_keys.make_pk_uri
|
||||||
let public_key_hash x = return (Signature.Public_key.hash x)
|
(Uri.make ~scheme ~path:(Signature.Public_key.to_b58check pk) ())
|
||||||
let sign ?watermark t buf = return (Signature.sign ?watermark t buf)
|
|
||||||
|
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)
|
||||||
|
@ -8,3 +8,6 @@
|
|||||||
(**************************************************************************)
|
(**************************************************************************)
|
||||||
|
|
||||||
include Client_keys.SIGNER
|
include Client_keys.SIGNER
|
||||||
|
|
||||||
|
val make_pk: Signature.public_key -> Client_keys.pk_uri
|
||||||
|
val make_sk: Signature.secret_key -> Client_keys.sk_uri
|
||||||
|
@ -103,7 +103,7 @@ let inject_endorsement (cctxt : #Proto_alpha.full)
|
|||||||
~slots
|
~slots
|
||||||
() >>=? fun bytes ->
|
() >>=? fun bytes ->
|
||||||
Client_keys.append
|
Client_keys.append
|
||||||
cctxt src_sk ~watermark:Endorsement bytes >>=? fun signed_bytes ->
|
src_sk ~watermark:Endorsement bytes >>=? fun signed_bytes ->
|
||||||
Shell_services.inject_operation
|
Shell_services.inject_operation
|
||||||
cctxt ?async ~chain_id:bi.chain_id signed_bytes >>=? fun oph ->
|
cctxt ?async ~chain_id:bi.chain_id signed_bytes >>=? fun oph ->
|
||||||
iter_s
|
iter_s
|
||||||
|
@ -31,8 +31,7 @@ let forge_block_header
|
|||||||
{ priority ; seed_nonce_hash ; proof_of_work_nonce } in
|
{ priority ; seed_nonce_hash ; proof_of_work_nonce } in
|
||||||
if Baking.check_header_proof_of_work_stamp shell protocol_data stamp_threshold then
|
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
|
let unsigned_header = Block_header.forge_unsigned shell protocol_data in
|
||||||
Client_keys.append cctxt
|
Client_keys.append delegate_sk ~watermark:Block_header unsigned_header
|
||||||
delegate_sk ~watermark:Block_header unsigned_header
|
|
||||||
else
|
else
|
||||||
loop () in
|
loop () in
|
||||||
loop ()
|
loop ()
|
||||||
|
@ -114,9 +114,10 @@ let vote_protocol_parameters =
|
|||||||
|
|
||||||
let activate_alpha ?(vote = false) () =
|
let activate_alpha ?(vote = false) () =
|
||||||
let fitness = Fitness_repr.from_int64 0L in
|
let fitness = Fitness_repr.from_int64 0L in
|
||||||
let dictator_sk = Client_keys.Secret_key_locator.create
|
let dictator_sk =
|
||||||
~scheme:"unencrypted"
|
Tezos_signer_backends.Unencrypted.make_sk
|
||||||
~location:["edsk31vznjHSSpGExDMHYASz45VZqXN4DPxvsa4hAyY8dHM28cZzp6"] in
|
(Signature.Secret_key.of_b58check_exn
|
||||||
|
"edsk31vznjHSSpGExDMHYASz45VZqXN4DPxvsa4hAyY8dHM28cZzp6") in
|
||||||
let protocol_parameters =
|
let protocol_parameters =
|
||||||
if vote then vote_protocol_parameters else protocol_parameters in
|
if vote then vote_protocol_parameters else protocol_parameters in
|
||||||
Tezos_client_genesis.Client_proto_main.bake
|
Tezos_client_genesis.Client_proto_main.bake
|
||||||
@ -248,9 +249,8 @@ module Account = struct
|
|||||||
~(account:t)
|
~(account:t)
|
||||||
~destination
|
~destination
|
||||||
~amount () =
|
~amount () =
|
||||||
let src_sk = Client_keys.Secret_key_locator.create
|
let src_sk =
|
||||||
~scheme:"unencrypted"
|
Tezos_signer_backends.Unencrypted.make_sk account.sk in
|
||||||
~location:[Signature.Secret_key.to_b58check account.sk] in
|
|
||||||
Client_proto_context.transfer
|
Client_proto_context.transfer
|
||||||
(new wrap_full (no_write_context !rpc_config ~block))
|
(new wrap_full (no_write_context !rpc_config ~block))
|
||||||
block
|
block
|
||||||
@ -272,9 +272,8 @@ module Account = struct
|
|||||||
let delegatable, delegate = match delegate with
|
let delegatable, delegate = match delegate with
|
||||||
| None -> false, None
|
| None -> false, None
|
||||||
| Some delegate -> true, Some delegate in
|
| Some delegate -> true, Some delegate in
|
||||||
let src_sk = Client_keys.Secret_key_locator.create
|
let src_sk =
|
||||||
~scheme:"unencrypted"
|
Tezos_signer_backends.Unencrypted.make_sk src.sk in
|
||||||
~location:[Signature.Secret_key.to_b58check src.sk] in
|
|
||||||
Client_proto_context.originate_account
|
Client_proto_context.originate_account
|
||||||
~source:src.contract
|
~source:src.contract
|
||||||
~src_pk:src.pk
|
~src_pk:src.pk
|
||||||
@ -506,9 +505,8 @@ module Baking = struct
|
|||||||
Some (Nonce.hash seed_nonce)
|
Some (Nonce.hash seed_nonce)
|
||||||
else
|
else
|
||||||
None in
|
None in
|
||||||
let src_sk = Client_keys.Secret_key_locator.create
|
let src_sk =
|
||||||
~scheme:"unencrypted"
|
Tezos_signer_backends.Unencrypted.make_sk contract.sk in
|
||||||
~location:[Signature.Secret_key.to_b58check contract.sk] in
|
|
||||||
Client_baking_forge.forge_block
|
Client_baking_forge.forge_block
|
||||||
ctxt
|
ctxt
|
||||||
block
|
block
|
||||||
|
@ -84,7 +84,7 @@ module Account : sig
|
|||||||
?block:Block_services.block ->
|
?block:Block_services.block ->
|
||||||
?fee: Tez.t ->
|
?fee: Tez.t ->
|
||||||
contract:Contract.t ->
|
contract:Contract.t ->
|
||||||
manager_sk:Client_keys.Secret_key_locator.t ->
|
manager_sk:Client_keys.sk_uri ->
|
||||||
src_pk:public_key ->
|
src_pk:public_key ->
|
||||||
public_key_hash option ->
|
public_key_hash option ->
|
||||||
Operation_hash.t tzresult Lwt.t
|
Operation_hash.t tzresult Lwt.t
|
||||||
|
@ -55,7 +55,7 @@ let transfer cctxt
|
|||||||
~destination ?parameters ~fee () >>=? fun bytes ->
|
~destination ?parameters ~fee () >>=? fun bytes ->
|
||||||
Block_services.predecessor cctxt block >>=? fun predecessor ->
|
Block_services.predecessor cctxt block >>=? fun predecessor ->
|
||||||
Client_keys.sign
|
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 signed_bytes = Signature.concat bytes signature in
|
||||||
let oph = Operation_hash.hash_bytes [ signed_bytes ] in
|
let oph = Operation_hash.hash_bytes [ signed_bytes ] in
|
||||||
Alpha_services.Helpers.apply_operation cctxt block
|
Alpha_services.Helpers.apply_operation cctxt block
|
||||||
@ -74,7 +74,7 @@ let reveal cctxt
|
|||||||
cctxt block
|
cctxt block
|
||||||
~branch ~source ~sourcePubKey:src_pk ~counter ~fee () >>=? fun bytes ->
|
~branch ~source ~sourcePubKey:src_pk ~counter ~fee () >>=? fun bytes ->
|
||||||
Client_keys.sign
|
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 signed_bytes = Signature.concat bytes signature in
|
||||||
let oph = Operation_hash.hash_bytes [ signed_bytes ] in
|
let oph = Operation_hash.hash_bytes [ signed_bytes ] in
|
||||||
Shell_services.inject_operation
|
Shell_services.inject_operation
|
||||||
@ -123,7 +123,7 @@ let originate_account ?branch
|
|||||||
~counter ~balance ~spendable:true
|
~counter ~balance ~spendable:true
|
||||||
?delegatable ?delegatePubKey:delegate ~fee () >>=? fun bytes ->
|
?delegatable ?delegatePubKey:delegate ~fee () >>=? fun bytes ->
|
||||||
Client_keys.sign
|
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
|
originate cctxt ~block ~chain_id ~signature bytes
|
||||||
|
|
||||||
let delegate_contract cctxt
|
let delegate_contract cctxt
|
||||||
@ -138,7 +138,7 @@ let delegate_contract cctxt
|
|||||||
~branch ~source ?sourcePubKey:src_pk ~counter ~fee delegate_opt
|
~branch ~source ?sourcePubKey:src_pk ~counter ~fee delegate_opt
|
||||||
>>=? fun bytes ->
|
>>=? fun bytes ->
|
||||||
Client_keys.sign
|
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 signed_bytes = Signature.concat bytes signature in
|
||||||
let oph = Operation_hash.hash_bytes [ signed_bytes ] in
|
let oph = Operation_hash.hash_bytes [ signed_bytes ] in
|
||||||
Shell_services.inject_operation
|
Shell_services.inject_operation
|
||||||
@ -241,7 +241,7 @@ let originate_contract
|
|||||||
~delegatable ?delegatePubKey:delegate
|
~delegatable ?delegatePubKey:delegate
|
||||||
~script:{ code ; storage } ~fee () >>=? fun bytes ->
|
~script:{ code ; storage } ~fee () >>=? fun bytes ->
|
||||||
Client_keys.sign
|
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
|
originate cctxt ~block ~signature bytes
|
||||||
|
|
||||||
let wait_for_operation_inclusion
|
let wait_for_operation_inclusion
|
||||||
@ -345,15 +345,17 @@ let claim_commitment (cctxt : #Proto_alpha.full)
|
|||||||
Shell_services.inject_operation
|
Shell_services.inject_operation
|
||||||
cctxt ~chain_id:bi.chain_id bytes >>=? fun oph ->
|
cctxt ~chain_id:bi.chain_id bytes >>=? fun oph ->
|
||||||
operation_submitted_message cctxt oph >>=? fun () ->
|
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
|
begin
|
||||||
match confirmations with
|
match confirmations with
|
||||||
| None ->
|
| 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 ()
|
return ()
|
||||||
| Some confirmations ->
|
| Some confirmations ->
|
||||||
cctxt#message "Waiting for the operation to be included..." >>= fun () ->
|
cctxt#message "Waiting for the operation to be included..." >>= fun () ->
|
||||||
wait_for_operation_inclusion ~confirmations cctxt oph >>=? 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
|
Alpha_services.Contract.balance
|
||||||
cctxt (`Head 0) (Contract.implicit_contract pkh) >>=? fun balance ->
|
cctxt (`Head 0) (Contract.implicit_contract pkh) >>=? fun balance ->
|
||||||
cctxt#message "Account %s (%a) created with %s%a."
|
cctxt#message "Account %s (%a) created with %s%a."
|
||||||
|
@ -119,7 +119,7 @@ let trace
|
|||||||
|
|
||||||
let hash_and_sign (data : Michelson_v1_parser.parsed) (typ : Michelson_v1_parser.parsed) sk block cctxt =
|
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 ->
|
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
|
let `Hex signature = Signature.to_hex signature in
|
||||||
return (hash, signature)
|
return (hash, signature)
|
||||||
|
|
||||||
|
@ -9,6 +9,7 @@
|
|||||||
tezos-shell-services
|
tezos-shell-services
|
||||||
tezos-client-base
|
tezos-client-base
|
||||||
tezos-rpc
|
tezos-rpc
|
||||||
|
tezos-signer-backends
|
||||||
bip39))
|
bip39))
|
||||||
(library_flags (:standard -linkall))
|
(library_flags (:standard -linkall))
|
||||||
(flags (:standard -w -9+27-30-32-40@8
|
(flags (:standard -w -9+27-30-32-40@8
|
||||||
|
@ -21,7 +21,7 @@ let bake cctxt ?(timestamp = Time.now ()) block command sk =
|
|||||||
let blk =
|
let blk =
|
||||||
Data_encoding.Binary.to_bytes_exn Block_header.encoding
|
Data_encoding.Binary.to_bytes_exn Block_header.encoding
|
||||||
{ shell = shell_header ; protocol_data } in
|
{ 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 []
|
Shell_services.inject_block cctxt signed_blk []
|
||||||
|
|
||||||
let int64_parameter =
|
let int64_parameter =
|
||||||
|
Loading…
Reference in New Issue
Block a user