Signer: add authorized keys mechanism

This commit is contained in:
Benjamin Canou 2018-06-06 10:49:53 +02:00
parent a8b2ab325e
commit 347a552396
17 changed files with 410 additions and 178 deletions

View File

@ -9,11 +9,35 @@
let log = Signer_logging.lwt_log_notice
let sign (cctxt : #Client_context.wallet) pkh data =
module Authorized_key =
Client_aliases.Alias (struct
include Signature.Public_key
let name = "authorized_key"
let to_source s = return (to_b58check s)
let of_source t = Lwt.return (of_b58check t)
end)
let sign
(cctxt : #Client_context.wallet)
Signer_messages.Sign.Request.{ pkh ; data ; signature } ~require_auth =
log "Request for signing %d bytes of data for key %a, magic byte = %02X"
(MBytes.length data)
Signature.Public_key_hash.pp pkh
(MBytes.get_uint8 data 0) >>= fun () ->
begin match require_auth, signature with
| false, _ -> return ()
| true, None -> failwith "missing authentication signature field"
| true, Some signature ->
let to_sign = Signer_messages.Sign.Request.to_sign ~pkh ~data in
Authorized_key.load cctxt >>=? fun keys ->
if List.fold_left
(fun acc (_, key) -> acc || Signature.check key signature to_sign)
false keys
then
return ()
else
failwith "invalid authentication signature"
end >>=? fun () ->
Client_keys.get_key cctxt pkh >>=? fun (name, _pkh, sk_uri) ->
log "Signing data for key %s" name >>= fun () ->
Client_keys.sign sk_uri data >>=? fun signature ->

View File

@ -9,19 +9,27 @@
let log = Signer_logging.lwt_log_notice
let run (cctxt : #Client_context.wallet) ~host ~port ~cert ~key =
let run (cctxt : #Client_context.wallet) ~host ~port ~cert ~key ~require_auth =
log "Accepting HTTPS requests on port %d" port >>= fun () ->
let mode : Conduit_lwt_unix.server =
`TLS (`Crt_file_path cert, `Key_file_path key, `No_password, `Port port) in
let dir = RPC_directory.empty in
let dir =
RPC_directory.register1 dir Signer_services.sign begin fun pkh () data ->
Handler.sign cctxt pkh data
RPC_directory.register1 dir Signer_services.sign begin fun pkh signature data ->
Handler.sign cctxt { pkh ; data ; signature } ~require_auth
end in
let dir =
RPC_directory.register1 dir Signer_services.public_key begin fun pkh () () ->
Handler.public_key cctxt pkh
end in
let dir =
RPC_directory.register0 dir Signer_services.authorized_keys begin fun () () ->
if require_auth then
return None
else
Handler.Authorized_key.load cctxt >>=? fun keys ->
return (Some (keys |> List.split |> snd |> List.map Signature.Public_key.hash))
end in
Lwt.catch
(fun () ->
RPC_server.launch ~host mode dir

View File

@ -9,4 +9,6 @@
val run:
#Client_context.io_wallet ->
host:string -> port:int -> cert:string -> key:string -> 'a tzresult Lwt.t
host:string -> port:int -> cert:string -> key:string ->
require_auth: bool ->
'a tzresult Lwt.t

View File

@ -38,7 +38,7 @@ let group =
{ Clic.name = "signer" ;
title = "Commands specific to the signing daemon" }
let commands =
let commands base_dir require_auth =
Client_keys_commands.commands () @
[ command ~group
~desc: "Launch a signer daemon over a TCP socket."
@ -63,7 +63,7 @@ let commands =
(prefixes [ "launch" ; "socket" ; "signer" ] @@ stop)
(fun (host, port) cctxt ->
Tezos_signer_backends.Encrypted.decrypt_all cctxt >>=? fun () ->
Socket_daemon.run cctxt (Tcp (host, port))) ;
Socket_daemon.run cctxt (Tcp (host, port)) ~require_auth) ;
command ~group
~desc: "Launch a signer daemon over a local Unix socket."
(args1
@ -72,12 +72,12 @@ let commands =
~short: 's'
~long: "socket"
~placeholder: "path"
~default: default_unix_path
~default: (Filename.concat base_dir "socket")
(parameter (fun _ s -> return s))))
(prefixes [ "launch" ; "local" ; "signer" ] @@ stop)
(fun path cctxt ->
Tezos_signer_backends.Encrypted.decrypt_all cctxt >>=? fun () ->
Socket_daemon.run cctxt (Unix path)) ;
Socket_daemon.run cctxt (Unix path) ~require_auth) ;
command ~group
~desc: "Launch a signer daemon over HTTPS."
(args2
@ -109,9 +109,31 @@ let commands =
(parameter (fun _ s -> return s)) @@ stop)
(fun (host, port) cert key cctxt ->
Tezos_signer_backends.Encrypted.decrypt_all cctxt >>=? fun () ->
Https_daemon.run cctxt ~host ~port ~cert ~key) ;
Https_daemon.run cctxt ~host ~port ~cert ~key ~require_auth) ;
command ~group
~desc: "Authorize a given public key to perform signing requests."
(args1
(arg
~doc: "an optional name for the key (defaults to the hash)"
~short: 'N'
~long: "name"
~placeholder: "name"
(parameter (fun _ s -> return s))))
(prefixes [ "add" ; "authorized" ; "key" ] @@
param
~name:"pk"
~desc: "full public key (Base58 encoded)"
(parameter (fun _ s -> Lwt.return (Signature.Public_key.of_b58check s))) @@
stop)
(fun name key cctxt ->
let pkh = Signature.Public_key.hash key in
let name = match name with
| Some name -> name
| None -> Signature.Public_key_hash.to_b58check pkh in
Handler.Authorized_key.add ~force:false cctxt name key)
]
let home = try Sys.getenv "HOME" with Not_found -> "/root"
let default_base_dir =
@ -132,9 +154,17 @@ let base_dir_arg () =
By default: '" ^ default_base_dir ^"'.")
(string_parameter ())
let require_auth_arg () =
switch
~long:"require-authentication"
~short:'A'
~doc:"Require a signature from the caller to sign."
()
let global_options () =
args1
args2
(base_dir_arg ())
(require_auth_arg ())
(* Main (lwt) entry *)
let main () =
@ -158,7 +188,7 @@ let main () =
begin
begin
parse_global_options
(global_options ()) () original_args >>=? fun (base_dir, remaining) ->
(global_options ()) () original_args >>=? fun ((base_dir, require_auth), remaining) ->
let base_dir = Option.unopt ~default:default_base_dir base_dir in
let cctxt = object
inherit Client_context_unix.unix_logger ~base_dir
@ -177,7 +207,7 @@ let main () =
~global_options:(global_options ())
(if Unix.isatty Unix.stdout then Clic.Ansi else Clic.Plain)
Format.std_formatter
commands in
(commands base_dir require_auth) in
begin match autocomplete with
| Some (prev_arg, cur_arg, script) ->
Clic.autocompletion

View File

@ -11,7 +11,7 @@ open Signer_messages
let log = Signer_logging.lwt_log_notice
let run (cctxt : #Client_context.wallet) path =
let run (cctxt : #Client_context.wallet) path ~require_auth =
Lwt_utils_unix.Socket.bind path >>=? fun fd ->
let rec loop () =
Lwt_unix.accept fd >>= fun (fd, _) ->
@ -19,7 +19,7 @@ let run (cctxt : #Client_context.wallet) path =
Lwt_utils_unix.Socket.recv fd Request.encoding >>=? function
| Sign req ->
let encoding = result_encoding Sign.Response.encoding in
Handler.sign cctxt req.pkh req.data >>= fun res ->
Handler.sign cctxt req ~require_auth >>= fun res ->
Lwt_utils_unix.Socket.send fd encoding res >>= fun _ ->
Lwt_unix.close fd >>= fun () ->
return ()
@ -29,6 +29,17 @@ let run (cctxt : #Client_context.wallet) path =
Lwt_utils_unix.Socket.send fd encoding res >>= fun _ ->
Lwt_unix.close fd >>= fun () ->
return ()
| Authorized_keys ->
let encoding = result_encoding Authorized_keys.Response.encoding in
begin if require_auth then
Handler.Authorized_key.load cctxt >>=? fun keys ->
return (Authorized_keys.Response.Authorized_keys
(keys |> List.split |> snd |> List.map Signature.Public_key.hash))
else return Authorized_keys.Response.No_authentication
end >>= fun res ->
Lwt_utils_unix.Socket.send fd encoding res >>= fun _ ->
Lwt_unix.close fd >>= fun () ->
return ()
end ;
loop ()
in

View File

@ -9,4 +9,6 @@
val run:
#Client_context.io_wallet ->
Lwt_utils_unix.Socket.addr -> 'a tzresult Lwt.t
Lwt_utils_unix.Socket.addr ->
require_auth: bool ->
'a tzresult Lwt.t

View File

@ -74,18 +74,6 @@ let main select_commands =
ignore Clic.(setup_formatter Format.err_formatter
(if Unix.isatty Unix.stderr then Ansi else Plain) Short) ;
init_logger () >>= fun () ->
Client_keys.register_signer
(module Tezos_signer_backends.Unencrypted) ;
Client_keys.register_signer
(module Tezos_signer_backends.Encrypted.Make(struct
let cctxt = new Client_context_unix.unix_prompter
end)) ;
Client_keys.register_signer
(module Tezos_signer_backends.Https) ;
Client_keys.register_signer
(module Tezos_signer_backends.Socket.Unix) ;
Client_keys.register_signer
(module Tezos_signer_backends.Socket.Tcp) ;
Lwt.catch begin fun () -> begin
Client_config.parse_config_args
(new unix_full
@ -102,14 +90,6 @@ let main select_commands =
tls = parsed_config_file.tls ;
} in
let ctxt = new RPC_client.http_ctxt rpc_config Media_type.all_media_types in
select_commands ctxt parsed_args >>=? fun commands ->
let commands =
Clic.add_manual
~executable_name
~global_options
(if Unix.isatty Unix.stdout then Clic.Ansi else Clic.Plain)
Format.std_formatter
(config_commands @ builtin_commands @ commands) in
let rpc_config =
if parsed_args.print_timings then
{ rpc_config with
@ -124,12 +104,48 @@ let main select_commands =
~confirmations:parsed_args.confirmations
~base_dir:parsed_config_file.base_dir
~rpc_config:rpc_config in
Client_keys.register_signer
(module Tezos_signer_backends.Unencrypted) ;
Client_keys.register_signer
(module Tezos_signer_backends.Encrypted.Make(struct
let cctxt = (client_config :> Client_context.prompter)
end)) ;
let module Remote_authenticator = struct
let authenticate pkhs payload =
Client_keys.list_keys client_config >>=? fun keys ->
match List.filter_map
(function
| (_, known_pkh, _, Some known_sk_uri)
when List.exists (fun pkh -> Signature.Public_key_hash.equal pkh known_pkh) pkhs ->
Some known_sk_uri
| _ -> None)
keys with
| sk_uri :: _ ->
Client_keys.sign sk_uri payload
| [] -> failwith
"remote signer expects authentication signature, \
but no authorized key was found in the wallet"
end in
let module Https = Tezos_signer_backends.Https.Make(Remote_authenticator) in
let module Socket = Tezos_signer_backends.Socket.Make(Remote_authenticator) in
Client_keys.register_signer (module Https) ;
Client_keys.register_signer (module Socket.Unix) ;
Client_keys.register_signer (module Socket.Tcp) ;
Option.iter parsed_config_file.remote_signer ~f: begin fun signer ->
Client_keys.register_signer
(module Tezos_signer_backends.Remote.Make(struct
let default = signer
include Remote_authenticator
end))
end ;
select_commands ctxt parsed_args >>=? fun commands ->
let commands =
Clic.add_manual
~executable_name
~global_options
(if Unix.isatty Unix.stdout then Clic.Ansi else Clic.Plain)
Format.std_formatter
(config_commands @ builtin_commands @ commands) in
begin match autocomplete with
| Some (prev_arg, cur_arg, script) ->
Clic.autocompletion

View File

@ -11,52 +11,73 @@ open Client_keys
let scheme = "https"
let title =
"Built-in tezos-signer using remote signer through hardcoded https requests."
module Make(P : sig
val authenticate: Signature.Public_key_hash.t list -> MBytes.t -> Signature.t tzresult Lwt.t
end) = struct
let description =
"Valid locators are of this form:\n\
\ - https://host/tz1...\n\
\ - https://host:port/path/to/service/tz1...\n"
let scheme = scheme
let parse uri =
(* extract `tz1..` from the last component of the path *)
assert (Uri.scheme uri = Some scheme) ;
let path = Uri.path uri in
begin match String.rindex_opt path '/' with
| None ->
failwith "Invalid locator %a" Uri.pp_hum uri
| Some i ->
let pkh = String.sub path (i + 1) (String.length path - i - 1) in
let path = String.sub path 0 i in
return (Uri.with_path uri path, pkh)
end >>=? fun (base, pkh) ->
Lwt.return (Signature.Public_key_hash.of_b58check pkh) >>=? fun pkh ->
return (base, pkh)
let title =
"Built-in tezos-signer using remote signer through hardcoded https requests."
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 description =
"Valid locators are of this form:\n\
\ - https://host/tz1...\n\
\ - https://host:port/path/to/service/tz1...\n"
let neuterize uri =
return (Client_keys.make_pk_uri (uri : sk_uri :> Uri.t))
let parse uri =
(* extract `tz1..` from the last component of the path *)
assert (Uri.scheme uri = Some scheme) ;
let path = Uri.path uri in
begin match String.rindex_opt path '/' with
| None ->
failwith "Invalid locator %a" Uri.pp_hum uri
| Some i ->
let pkh = String.sub path (i + 1) (String.length path - i - 1) in
let path = String.sub path 0 i in
return (Uri.with_path uri path, pkh)
end >>=? fun (base, pkh) ->
Lwt.return (Signature.Public_key_hash.of_b58check pkh) >>=? fun pkh ->
return (base, pkh)
let public_key_hash uri =
public_key uri >>=? fun pk ->
return (Signature.Public_key.hash pk)
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 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
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.authorized_keys () () () >>=? fun authorized_keys ->
begin match authorized_keys with
| Some authorized_keys ->
P.authenticate
authorized_keys
(Signer_messages.Sign.Request.to_sign ~pkh ~data:msg) >>=? fun signature ->
return (Some signature)
| None -> return None
end >>=? fun signature ->
RPC_client.call_service
Media_type.all_media_types
~base Signer_services.sign ((), pkh)
signature
msg
end
let make_base host port =
Uri.make ~scheme ~host ~port ()

View File

@ -7,6 +7,9 @@
(* *)
(**************************************************************************)
include Client_keys.SIGNER
module Make(P : sig
val authenticate: Signature.Public_key_hash.t list -> MBytes.t -> Signature.t tzresult Lwt.t
end)
: Client_keys.SIGNER
val make_base: string -> int -> Uri.t

View File

@ -11,7 +11,10 @@ open Client_keys
let scheme = "remote"
module Make(S : sig val default : Uri.t end) = struct
module Make(S : sig
val default : Uri.t
val authenticate: Signature.Public_key_hash.t list -> MBytes.t -> Signature.t tzresult Lwt.t
end) = struct
let scheme = scheme
@ -27,6 +30,9 @@ module Make(S : sig val default : Uri.t end) = struct
- $TEZOS_SIGNER_TCP_HOST and $TEZOS_SIGNER_TCP_PORT (default: 7732),\n\
- $TEZOS_SIGNER_HTTPS_HOST and $TEZOS_SIGNER_HTTPS_PORT (default: 443)."
module Socket = Socket.Make(S)
module Https = Https.Make(S)
let get_remote () =
match Uri.scheme S.default with
| Some "unix" -> (module Socket.Unix : SIGNER)

View File

@ -7,7 +7,10 @@
(* *)
(**************************************************************************)
module Make(S : sig val default : Uri.t end) : Client_keys.SIGNER
module Make(S : sig
val default : Uri.t
val authenticate: Signature.Public_key_hash.t list -> MBytes.t -> Signature.t tzresult Lwt.t
end) : Client_keys.SIGNER
val make_pk: Signature.public_key -> Client_keys.pk_uri
val make_sk: Signature.secret_key -> Client_keys.sk_uri

View File

@ -10,108 +10,129 @@
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 tcp_scheme = "tcp"
let unix_scheme = "unix"
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 Make(P : sig
val authenticate: Signature.Public_key_hash.t list -> MBytes.t -> Signature.t tzresult Lwt.t
end) = struct
module Unix = struct
let sign ?watermark path pkh msg =
let msg =
match watermark with
| None -> msg
| Some watermark ->
MBytes.concat "" [ Signature.bytes_of_watermark watermark ; msg ] in
Lwt_utils_unix.Socket.connect path >>=? fun conn ->
Lwt_utils_unix.Socket.send
conn Request.encoding Request.Authorized_keys >>=? fun () ->
Lwt_utils_unix.Socket.recv conn
Authorized_keys.Response.encoding >>=? fun authorized_keys ->
begin match authorized_keys with
| No_authentication -> return None
| Authorized_keys authorized_keys ->
P.authenticate authorized_keys
(Sign.Request.to_sign ~pkh ~data:msg) >>=? fun signature ->
return (Some signature)
end >>=? fun signature ->
let req = { Sign.Request.pkh ; data = msg ; signature } in
Lwt_utils_unix.Socket.send
conn Request.encoding (Request.Sign req) >>=? fun () ->
Lwt_utils_unix.Socket.recv conn
(result_encoding Sign.Response.encoding) >>=? fun res ->
Lwt_unix.close conn >>= fun () ->
Lwt.return res
let scheme = "unix"
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
let title =
"Built-in tezos-signer using remote signer through hardcoded unix socket."
module Unix = struct
let description =
"Valid locators are of this form: unix:///path/to/socket?pkh=tz1..."
let scheme = unix_scheme
let parse uri =
assert (Uri.scheme uri = Some scheme) ;
trace (Invalid_uri uri) @@
match Uri.get_query_param uri "pkh" with
| None -> failwith "Missing the query parameter: 'pkh=tz1...'"
| Some key ->
Lwt.return (Signature.Public_key_hash.of_b58check key) >>=? fun key ->
return (Lwt_utils_unix.Socket.Unix (Uri.path uri), key)
let title =
"Built-in tezos-signer using remote signer through hardcoded unix socket."
let public_key uri =
parse (uri : pk_uri :> Uri.t) >>=? fun (path, pkh) ->
public_key path pkh
let description =
"Valid locators are of this form: unix:///path/to/socket?pkh=tz1..."
let neuterize uri =
return (Client_keys.make_pk_uri (uri : sk_uri :> Uri.t))
let parse uri =
assert (Uri.scheme uri = Some scheme) ;
trace (Invalid_uri uri) @@
match Uri.get_query_param uri "pkh" with
| None -> failwith "Missing the query parameter: 'pkh=tz1...'"
| 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_hash uri =
public_key uri >>=? fun pk ->
return (Signature.Public_key.hash pk)
let public_key uri =
parse (uri : pk_uri :> Uri.t) >>=? fun (path, pkh) ->
public_key path pkh
let sign ?watermark uri msg =
parse (uri : sk_uri :> Uri.t) >>=? fun (path, pkh) ->
sign ?watermark path pkh msg
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_scheme
let title =
"Built-in tezos-signer using remote signer through hardcoded tcp socket."
let description =
"Valid locators are of this form: tcp://host:port/tz1..."
let parse uri =
assert (Uri.scheme uri = Some scheme) ;
trace (Invalid_uri uri) @@
match Uri.host uri, Uri.port uri with
| None, _ ->
failwith "Missing host address"
| _, None ->
failwith "Missing host port"
| Some path, Some port ->
Lwt.return
(Signature.Public_key_hash.of_b58check (Uri.path uri)) >>=? fun pkh ->
return (Lwt_utils_unix.Socket.Tcp (path, port), pkh)
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
end
module Tcp = struct
let scheme = "tcp"
let title =
"Built-in tezos-signer using remote signer through hardcoded tcp socket."
let description =
"Valid locators are of this form: tcp://host:port/tz1..."
let parse uri =
assert (Uri.scheme uri = Some scheme) ;
trace (Invalid_uri uri) @@
match Uri.host uri, Uri.port uri with
| None, _ ->
failwith "Missing host address"
| _, None ->
failwith "Missing host port"
| Some path, Some port ->
Lwt.return
(Signature.Public_key_hash.of_b58check (Uri.path uri)) >>=? fun pkh ->
return (Lwt_utils_unix.Socket.Tcp (path, port), pkh)
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
let make_unix_base path =
Uri.make ~scheme:Unix.scheme ~path ()
Uri.make ~scheme:unix_scheme ~path ()
let make_tcp_base host port =
Uri.make ~scheme:Tcp.scheme ~host ~port ()
Uri.make ~scheme:tcp_scheme ~host ~port ()

View File

@ -7,8 +7,12 @@
(* *)
(**************************************************************************)
module Unix : Client_keys.SIGNER
module Tcp : Client_keys.SIGNER
module Make(P : sig
val authenticate: Signature.Public_key_hash.t list -> MBytes.t -> Signature.t tzresult Lwt.t
end) : sig
module Unix : Client_keys.SIGNER
module Tcp : Client_keys.SIGNER
end
val make_unix_base: string -> Uri.t
val make_tcp_base: string -> int -> Uri.t

View File

@ -14,18 +14,26 @@ module Sign = struct
type t = {
pkh: Signature.Public_key_hash.t ;
data: MBytes.t ;
signature: Signature.t option ;
}
let to_sign ~pkh ~data =
MBytes.concat ""
[ MBytes.of_hex (`Hex "04") ;
Signature.Public_key_hash.to_bytes pkh ;
data ]
let encoding =
let open Data_encoding in
conv
(fun { pkh ; data } ->
(pkh, data))
(fun (pkh, data) ->
{ pkh ; data })
(obj2
(fun { pkh ; data ; signature } ->
(pkh, data, signature))
(fun (pkh, data, signature) ->
{ pkh ; data ; signature })
(obj3
(req "pkh" Signature.Public_key_hash.encoding)
(req "data" bytes))
(req "data" bytes)
(opt "signature" Signature.encoding))
end
@ -62,11 +70,38 @@ module Public_key = struct
end
module Authorized_keys = struct
module Response = struct
type t =
| No_authentication
| Authorized_keys of Signature.Public_key_hash.t list
let encoding =
let open Data_encoding in
union
[ case (Tag 0)
~title: "No_authentication"
(constant "no_authentication_required")
(function No_authentication -> Some () | _ -> None)
(fun () -> No_authentication) ;
case (Tag 1)
~title: "Authorized_keys"
(list Signature.Public_key_hash.encoding)
(function Authorized_keys l -> Some l | _ -> None)
(fun l -> Authorized_keys l) ]
end
end
module Request = struct
type t =
| Sign of Sign.Request.t
| Public_key of Public_key.Request.t
| Authorized_keys
let encoding =
let open Data_encoding in
@ -85,6 +120,11 @@ module Request = struct
Public_key.Request.encoding)
(function Public_key req -> Some ((), req) | _ -> None)
(fun ((), req) -> Public_key req) ;
case (Tag 2)
~title:"Authorized_keys"
(obj1 (req "kind" (constant "authorized_keys")))
(function Authorized_keys -> Some () | _ -> None)
(fun () -> Authorized_keys) ;
]
end

View File

@ -13,7 +13,12 @@ module Sign : sig
type t = {
pkh: Signature.Public_key_hash.t ;
data: MBytes.t ;
signature: Signature.t option ;
}
val to_sign:
pkh: Signature.Public_key_hash.t ->
data: MBytes.t ->
MBytes.t
val encoding : t Data_encoding.t
end
@ -38,11 +43,23 @@ module Public_key : sig
end
module Authorized_keys : sig
module Response : sig
type t =
| No_authentication
| Authorized_keys of Signature.Public_key_hash.t list
val encoding : t Data_encoding.t
end
end
module Request : sig
type t =
| Sign of Sign.Request.t
| Public_key of Public_key.Request.t
| Authorized_keys
val encoding : t Data_encoding.t
end

View File

@ -8,11 +8,21 @@
(**************************************************************************)
let sign =
let query =
let open RPC_query in
query (fun signature -> signature)
|+ opt_field
~descr: "Must be provided if the signer requires \
authentication. In this case, it must be the signature \
of the public key hash and message concatenated, by one \
of the keys authorized by the signer."
"authentication" Signature.rpc_arg (fun signature -> signature)
|> seal in
RPC_service.post_service
~description: "Sign a piece of data with a given remote key"
~query: RPC_query.empty
~query
~input: Data_encoding.bytes
~output: Data_encoding.(obj1 (req "signature" Signature.encoding))
~output: Data_encoding.(obj1 (req "signature" Signature.encoding))
RPC_path.(root /: Signature.Public_key_hash.rpc_arg)
let public_key =
@ -21,3 +31,13 @@ let public_key =
~query: RPC_query.empty
~output: Data_encoding.(obj1 (req "public_key" Signature.Public_key.encoding))
RPC_path.(root /: Signature.Public_key_hash.rpc_arg)
let authorized_keys =
RPC_service.get_service
~description: "Retrieve the public keys that can be used to \
authenticate signing commands.\n\
If the empty object is returned, the signer has \
been set to accept unsigned commands."
~query: RPC_query.empty
~output: Data_encoding.(obj1 (opt "authorized_keys" (list Signature.Public_key_hash.encoding)))
RPC_path.(root / "authorized_keys")

View File

@ -9,8 +9,12 @@
val sign :
([ `POST ], unit, unit * Signature.Public_key_hash.t,
unit, MBytes.t, Signature.t) RPC_service.t
Signature.t option, MBytes.t, Signature.t) RPC_service.t
val public_key :
([ `GET ], unit, unit * Signature.Public_key_hash.t,
unit, unit, Signature.Public_key.t) RPC_service.t
val authorized_keys :
([ `GET ], unit, unit,
unit, unit, Signature.Public_key_hash.t list option) RPC_service.t