diff --git a/src/bin_signer/handler.ml b/src/bin_signer/handler.ml index f56c5b9fc..886a7af53 100644 --- a/src/bin_signer/handler.ml +++ b/src/bin_signer/handler.ml @@ -116,6 +116,22 @@ let check_magic_byte magic_bytes data = else failwith "magic byte 0x%02X not allowed" byte + +let check_authorization cctxt pkh data require_auth signature = + match require_auth, signature with + | false, _ -> return_unit + | 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_unit + else + failwith "invalid authentication signature" + let sign (cctxt : #Client_context.wallet) Signer_messages.Sign.Request.{ pkh ; data ; signature } @@ -127,20 +143,7 @@ let sign -% a Signature.Public_key_hash.Logging.tag pkh -% s magic_byte (MBytes.get_uint8 data 0)) >>= fun () -> check_magic_byte magic_bytes data >>=? fun () -> - begin match require_auth, signature with - | false, _ -> return_unit - | 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_unit - else - failwith "invalid authentication signature" - end >>=? fun () -> + check_authorization cctxt pkh data require_auth signature >>=? fun () -> Client_keys.get_key cctxt pkh >>=? fun (name, _pkh, sk_uri) -> log Tag.DSL.(fun f -> f "Signing data for key %s" @@ -152,6 +155,40 @@ let sign else sign data +let deterministic_nonce + (cctxt : #Client_context.wallet) + Signer_messages.Deterministic_nonce.Request.{ pkh ; data ; signature } + ~require_auth = + log Tag.DSL.(fun f -> + f "Request for creating a nonce from %d input bytes for key %a" + -% t event "request_for_deterministic_nonce" + -% s num_bytes (MBytes.length data) + -% a Signature.Public_key_hash.Logging.tag pkh) >>= fun () -> + check_authorization cctxt pkh data require_auth signature >>=? fun () -> + Client_keys.get_key cctxt pkh >>=? fun (name, _pkh, sk_uri) -> + log Tag.DSL.(fun f -> + f "Creating nonce for key %s" + -% t event "creating_nonce" + -% s Client_keys.Logging.tag name) >>= fun () -> + Client_keys.deterministic_nonce sk_uri data + +let deterministic_nonce_hash + (cctxt : #Client_context.wallet) + Signer_messages.Deterministic_nonce_hash.Request.{ pkh ; data ; signature } + ~require_auth = + log Tag.DSL.(fun f -> + f "Request for creating a nonce hash from %d input bytes for key %a" + -% t event "request_for_deterministic_nonce_hash" + -% s num_bytes (MBytes.length data) + -% a Signature.Public_key_hash.Logging.tag pkh) >>= fun () -> + check_authorization cctxt pkh data require_auth signature >>=? fun () -> + Client_keys.get_key cctxt pkh >>=? fun (name, _pkh, sk_uri) -> + log Tag.DSL.(fun f -> + f "Creating nonce hash for key %s" + -% t event "creating_nonce_hash" + -% s Client_keys.Logging.tag name) >>= fun () -> + Client_keys.deterministic_nonce_hash sk_uri data + let public_key (cctxt : #Client_context.wallet) pkh = log Tag.DSL.(fun f -> f "Request for public key %a" diff --git a/src/bin_signer/handler.mli b/src/bin_signer/handler.mli index e1a74f6ea..5dea278e0 100644 --- a/src/bin_signer/handler.mli +++ b/src/bin_signer/handler.mli @@ -40,3 +40,18 @@ val sign : check_high_watermark:bool -> require_auth:bool -> Signature.t tzresult Lwt.t (** [sign cctxt req ?magic_bytes ~check_high_watermark ~require_auth] signs [req] and returns a signature. *) + +val deterministic_nonce : + #Client_context.wallet -> + Signer_messages.Deterministic_nonce.Request.t -> + require_auth:bool -> MBytes.t tzresult Lwt.t +(** [deterministic_nonce cctxt req ~require_auth] generates + deterministically a nonce from [req.data]. *) + +val deterministic_nonce_hash : + #Client_context.wallet -> + Signer_messages.Deterministic_nonce_hash.Request.t -> + require_auth:bool -> MBytes.t tzresult Lwt.t +(** [deterministic_nonce_hash cctxt req ~require_auth] generates + deterministically a nonce from [req.data] and returns the hash of + this nonce. *) diff --git a/src/bin_signer/main_signer.ml b/src/bin_signer/main_signer.ml index daeb4401a..8c5e0c2df 100644 --- a/src/bin_signer/main_signer.ml +++ b/src/bin_signer/main_signer.ml @@ -224,7 +224,7 @@ let commands base_dir require_auth = (prefixes [ "launch" ; "https" ; "signer" ] @@ param ~name:"cert" - ~desc: "path to th TLS certificate" + ~desc: "path to the TLS certificate" (parameter (fun _ s -> if not (Sys.file_exists s) then failwith "No such TLS certificate file %s" s @@ -232,7 +232,7 @@ let commands base_dir require_auth = return s)) @@ param ~name:"key" - ~desc: "path to th TLS key" + ~desc: "path to the TLS key" (parameter (fun _ s -> if not (Sys.file_exists s) then failwith "No such TLS key file %s" s diff --git a/src/bin_signer/socket_daemon.ml b/src/bin_signer/socket_daemon.ml index a588e0e66..2102900ac 100644 --- a/src/bin_signer/socket_daemon.ml +++ b/src/bin_signer/socket_daemon.ml @@ -36,6 +36,18 @@ let handle_client ?magic_bytes ~check_high_watermark ~require_auth cctxt fd = Lwt_utils_unix.Socket.send fd encoding res >>= fun _ -> Lwt_unix.close fd >>= fun () -> return_unit + | Deterministic_nonce req -> + let encoding = result_encoding Deterministic_nonce.Response.encoding in + Handler.deterministic_nonce cctxt req ~require_auth >>= fun res -> + Lwt_utils_unix.Socket.send fd encoding res >>= fun _ -> + Lwt_unix.close fd >>= fun () -> + return_unit + | Deterministic_nonce_hash req -> + let encoding = result_encoding Deterministic_nonce_hash.Response.encoding in + Handler.deterministic_nonce_hash cctxt req ~require_auth >>= fun res -> + Lwt_utils_unix.Socket.send fd encoding res >>= fun _ -> + Lwt_unix.close fd >>= fun () -> + return_unit | Public_key pkh -> let encoding = result_encoding Public_key.Response.encoding in Handler.public_key cctxt pkh >>= fun res -> diff --git a/src/lib_client_base/client_keys.ml b/src/lib_client_base/client_keys.ml index 7c441af23..3f7f74576 100644 --- a/src/lib_client_base/client_keys.ml +++ b/src/lib_client_base/client_keys.ml @@ -153,6 +153,8 @@ module type SIGNER = sig val sign : ?watermark: Signature.watermark -> sk_uri -> MBytes.t -> Signature.t tzresult Lwt.t + val deterministic_nonce : sk_uri -> MBytes.t -> MBytes.t tzresult Lwt.t + val deterministic_nonce_hash : sk_uri -> MBytes.t -> MBytes.t tzresult Lwt.t end let signers_table : (string, (module SIGNER)) Hashtbl.t = Hashtbl.create 13 @@ -232,6 +234,18 @@ let check ?watermark pk_uri signature buf = public_key pk_uri >>=? fun pk -> return (Signature.check ?watermark pk signature buf) +let deterministic_nonce sk_uri data = + 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.deterministic_nonce sk_uri data + +let deterministic_nonce_hash sk_uri data = + 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.deterministic_nonce_hash sk_uri data + let register_key cctxt ?(force=false) (public_key_hash, pk_uri, sk_uri) ?public_key name = Public_key.add ~force cctxt name (pk_uri, public_key) >>=? fun () -> Secret_key.add ~force cctxt name sk_uri >>=? fun () -> diff --git a/src/lib_client_base/client_keys.mli b/src/lib_client_base/client_keys.mli index 33c193fca..bfc3a12cd 100644 --- a/src/lib_client_base/client_keys.mli +++ b/src/lib_client_base/client_keys.mli @@ -70,7 +70,7 @@ module type SIGNER = sig val public_key : ?interactive: Client_context.io_wallet -> 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]. Some signer implementations improve long-term security by requiring human/manual validation while importing keys, the @@ -90,9 +90,18 @@ module type SIGNER = sig val sign : ?watermark: Signature.watermark -> 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]. *) + val deterministic_nonce : + sk_uri -> MBytes.t -> MBytes.t tzresult Lwt.t + (** [deterministic_nonce sk data] is a nonce obtained + deterministically from [data] and [sk]. *) + + val deterministic_nonce_hash : + sk_uri -> MBytes.t -> MBytes.t tzresult Lwt.t + (** [deterministic_nonce_hash sk data] is a nonce hash obtained + deterministically from [data] and [sk]. *) end val register_signer : (module SIGNER) -> unit @@ -125,6 +134,12 @@ val check : ?watermark:Signature.watermark -> pk_uri -> Signature.t -> MBytes.t -> bool tzresult Lwt.t +val deterministic_nonce : + sk_uri -> MBytes.t -> MBytes.t tzresult Lwt.t + +val deterministic_nonce_hash : + sk_uri -> MBytes.t -> MBytes.t tzresult Lwt.t + val register_key : #Client_context.wallet -> ?force:bool -> @@ -160,4 +175,3 @@ val force_switch : unit -> (bool, 'ctx) Clic.arg val make_pk_uri : Uri.t -> pk_uri val make_sk_uri : Uri.t -> sk_uri - diff --git a/src/lib_crypto/ed25519.ml b/src/lib_crypto/ed25519.ml index d23fe06bc..6a646e459 100644 --- a/src/lib_crypto/ed25519.ml +++ b/src/lib_crypto/ed25519.ml @@ -343,6 +343,14 @@ let generate_key ?seed () = let pk = Sign.neuterize sk in Public_key.hash pk, pk, sk + +let deterministic_nonce sk msg = + Hash.SHA256.HMAC.digest ~key: (Secret_key.to_bytes sk) ~msg + +let deterministic_nonce_hash sk msg = + Blake2B.to_bytes (Blake2B.hash_bytes [deterministic_nonce sk msg]) + + include Compare.Make(struct type nonrec t = t let compare = MBytes.compare diff --git a/src/lib_crypto/p256.ml b/src/lib_crypto/p256.ml index f46915f13..19fe0bb8d 100644 --- a/src/lib_crypto/p256.ml +++ b/src/lib_crypto/p256.ml @@ -282,6 +282,13 @@ let generate_key ?(seed=Rand.generate 32) () = let pkh = Public_key.hash pk in pkh, pk, sk +let deterministic_nonce sk msg = + Hacl.Hash.SHA256.HMAC.digest ~key: (Secret_key.to_bytes sk) ~msg + +let deterministic_nonce_hash sk msg = + Blake2B.to_bytes (Blake2B.hash_bytes [deterministic_nonce sk msg]) + + include Compare.Make(struct type nonrec t = t let compare = MBytes.compare diff --git a/src/lib_crypto/s.ml b/src/lib_crypto/s.ml index a1fa11be6..75c1722a0 100644 --- a/src/lib_crypto/s.ml +++ b/src/lib_crypto/s.ml @@ -247,4 +247,8 @@ module type SIGNATURE = sig val generate_key: ?seed:MBytes.t -> unit -> (Public_key_hash.t * Public_key.t * Secret_key.t) + val deterministic_nonce: Secret_key.t -> MBytes.t -> MBytes.t + + val deterministic_nonce_hash: Secret_key.t -> MBytes.t -> MBytes.t + end diff --git a/src/lib_crypto/secp256k1.ml b/src/lib_crypto/secp256k1.ml index 529cb9212..862af9bdf 100644 --- a/src/lib_crypto/secp256k1.ml +++ b/src/lib_crypto/secp256k1.ml @@ -285,3 +285,9 @@ let generate_key ?(seed=Rand.generate 32) () = let pk = Key.neuterize_exn context sk in let pkh = Public_key.hash pk in pkh, pk, sk + +let deterministic_nonce sk msg = + Hacl.Hash.SHA256.HMAC.digest ~key: (Secret_key.to_bytes sk) ~msg + +let deterministic_nonce_hash sk msg = + Blake2B.to_bytes (Blake2B.hash_bytes [deterministic_nonce sk msg]) diff --git a/src/lib_crypto/signature.ml b/src/lib_crypto/signature.ml index bc7f17967..2d1818652 100644 --- a/src/lib_crypto/signature.ml +++ b/src/lib_crypto/signature.ml @@ -601,3 +601,15 @@ let generate_key ?(algo = Ed25519) ?seed () = let pkh, pk, sk = P256.generate_key ?seed () in (Public_key_hash.P256 pkh, Public_key.P256 pk, Secret_key.P256 sk) + +let deterministic_nonce sk msg = + match sk with + | Secret_key.Ed25519 sk -> Ed25519.deterministic_nonce sk msg + | Secret_key.Secp256k1 sk -> Secp256k1.deterministic_nonce sk msg + | Secret_key.P256 sk -> P256.deterministic_nonce sk msg + +let deterministic_nonce_hash sk msg = + match sk with + | Secret_key.Ed25519 sk -> Ed25519.deterministic_nonce_hash sk msg + | Secret_key.Secp256k1 sk -> Secp256k1.deterministic_nonce_hash sk msg + | Secret_key.P256 sk -> P256.deterministic_nonce_hash sk msg diff --git a/src/lib_signer_backends/encrypted.ml b/src/lib_signer_backends/encrypted.ml index 4087cd960..dceac1cf8 100644 --- a/src/lib_signer_backends/encrypted.ml +++ b/src/lib_signer_backends/encrypted.ml @@ -262,12 +262,23 @@ module Make(C : sig val cctxt: Client_context.prompter end) = struct where is the public key in Base58." 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) + let deterministic_nonce sk_uri buf = + decrypt C.cctxt sk_uri >>=? fun sk -> + return (Signature.deterministic_nonce sk buf) + + let deterministic_nonce_hash sk_uri buf = + decrypt C.cctxt sk_uri >>=? fun sk -> + return (Signature.deterministic_nonce_hash sk buf) + end diff --git a/src/lib_signer_backends/http_gen.ml b/src/lib_signer_backends/http_gen.ml index 8c38d0202..1a20bfe23 100644 --- a/src/lib_signer_backends/http_gen.ml +++ b/src/lib_signer_backends/http_gen.ml @@ -100,6 +100,20 @@ module Make(N : sig val scheme : string end) = struct public_key ?interactive uri >>=? fun pk -> return (Signature.Public_key.hash pk, Some pk) + let get_signature base pkh msg = + RPC_client.call_service + ~logger: P.logger + ?headers + Media_type.all_media_types + ~base Signer_services.authorized_keys () () () + >>=? function + | Some authorized_keys -> + P.authenticate + authorized_keys + (Signer_messages.Sign.Request.to_sign ~pkh ~data:msg) >>=? fun signature -> + return_some signature + | None -> return_none + let sign ?watermark uri msg = parse (uri : sk_uri :> Uri.t) >>=? fun (base, pkh) -> let msg = @@ -107,19 +121,7 @@ module Make(N : sig val scheme : string end) = struct | None -> msg | Some watermark -> MBytes.concat "" [ Signature.bytes_of_watermark watermark ; msg ] in - RPC_client.call_service - ~logger: P.logger - ?headers - 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 -> + get_signature base pkh msg >>=? fun signature -> RPC_client.call_service ~logger: P.logger ?headers @@ -128,6 +130,28 @@ module Make(N : sig val scheme : string end) = struct signature msg + let deterministic_nonce uri msg = + parse (uri : sk_uri :> Uri.t) >>=? fun (base, pkh) -> + get_signature base pkh msg >>=? fun signature -> + RPC_client.call_service + ~logger: P.logger + ?headers + Media_type.all_media_types + ~base Signer_services.deterministic_nonce ((), pkh) + signature + msg + + let deterministic_nonce_hash uri msg = + parse (uri : sk_uri :> Uri.t) >>=? fun (base, pkh) -> + get_signature base pkh msg >>=? fun signature -> + RPC_client.call_service + ~logger: P.logger + ?headers + Media_type.all_media_types + ~base Signer_services.deterministic_nonce_hash ((), pkh) + signature + msg + end let make_base host port = diff --git a/src/lib_signer_backends/ledger.ml b/src/lib_signer_backends/ledger.ml index 4d5fc9467..dda70ba84 100644 --- a/src/lib_signer_backends/ledger.ml +++ b/src/lib_signer_backends/ledger.ml @@ -105,6 +105,7 @@ let secp256k1_ctx = type error += | LedgerError of Ledgerwallet.Transport.error + | Ledger_deterministic_nonce_not_implemented let error_encoding = let open Data_encoding in @@ -125,6 +126,20 @@ let () = (function LedgerError e -> Some e | _ -> None) (fun e -> LedgerError e) +let () = + register_error_kind + `Permanent + ~id: "signer.ledger.deterministic_nonce_not_implemented" + ~title: "Ledger deterministic_nonce(_hash) not implemented" + ~description: "The deterministic_nonce(_hash) functionality \ + is not implemented by the ledger" + ~pp:(fun ppf () -> + Format.fprintf ppf "Asked the ledger to generate a deterministic nonce (hash), \ + but this functionality is not yet implemented") + Data_encoding.unit + (function Ledger_deterministic_nonce_not_implemented -> Some () | _ -> None) + (fun () -> Ledger_deterministic_nonce_not_implemented) + type id = | Animals of Ledger_names.t * Ledgerwallet_tezos.curve option | Pkh of Signature.Public_key_hash.t @@ -481,6 +496,10 @@ let sign ?watermark sk_uri msg = return (Signature.of_p256 signature) end +let deterministic_nonce _ _ = fail Ledger_deterministic_nonce_not_implemented +let deterministic_nonce_hash _ _ = fail Ledger_deterministic_nonce_not_implemented +let supports_deterministic_nonces _ = return_false + let commands = let open Clic in let group = diff --git a/src/lib_signer_backends/remote.ml b/src/lib_signer_backends/remote.ml index d093737a6..98caf625f 100644 --- a/src/lib_signer_backends/remote.ml +++ b/src/lib_signer_backends/remote.ml @@ -97,6 +97,16 @@ module Make(S : sig (Client_keys.make_sk_uri (key (sk_uri : sk_uri :> Uri.t))) msg + let deterministic_nonce sk_uri msg = + Remote.deterministic_nonce + (Client_keys.make_sk_uri (key (sk_uri : sk_uri :> Uri.t))) + msg + + let deterministic_nonce_hash sk_uri msg = + Remote.deterministic_nonce_hash + (Client_keys.make_sk_uri (key (sk_uri : sk_uri :> Uri.t))) + msg + end let make_sk sk = @@ -186,4 +196,3 @@ let parse_base_uri s = | Some scheme -> failwith "Unknown scheme: %s" scheme | None -> failwith "Unknown scheme: " with Invalid_argument msg -> failwith "Malformed URI: %s" msg - diff --git a/src/lib_signer_backends/socket.ml b/src/lib_signer_backends/socket.ml index f8c702a2c..718f995cd 100644 --- a/src/lib_signer_backends/socket.ml +++ b/src/lib_signer_backends/socket.ml @@ -33,12 +33,22 @@ module Make(P : sig val authenticate: Signature.Public_key_hash.t list -> MBytes.t -> Signature.t tzresult Lwt.t end) = 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 + type request_type = + | Sign_request + | Deterministic_nonce_request + | Deterministic_nonce_hash_request + + let build_request pkh data signature = function + | Sign_request -> + Request.Sign { Sign.Request.pkh ; data ; signature } + | Deterministic_nonce_request -> + Request.Deterministic_nonce + { Deterministic_nonce.Request.pkh ; data ; signature } + | Deterministic_nonce_hash_request -> + Request.Deterministic_nonce_hash + { Deterministic_nonce_hash.Request.pkh ; data ; signature } + + let signer_operation path pkh msg request_type = begin Lwt_utils_unix.Socket.connect path >>=? fun conn -> Lwt_utils_unix.Socket.send @@ -55,15 +65,37 @@ module Make(P : sig return_some signature end end >>=? fun signature -> - let req = { Sign.Request.pkh ; data = msg ; signature } in Lwt_utils_unix.Socket.connect path >>=? fun conn -> - Lwt_utils_unix.Socket.send - conn Request.encoding (Request.Sign req) >>=? fun () -> + let req = build_request pkh msg signature request_type in + Lwt_utils_unix.Socket.send conn Request.encoding req >>=? fun () -> + return conn + + let sign ?watermark path pkh msg = + let msg = + match watermark with + | None -> msg + | Some watermark -> + MBytes.concat "" [ Signature.bytes_of_watermark watermark ; msg ] in + signer_operation path pkh msg Sign_request >>=? fun conn -> Lwt_utils_unix.Socket.recv conn (result_encoding Sign.Response.encoding) >>=? fun res -> Lwt_unix.close conn >>= fun () -> Lwt.return res + let deterministic_nonce path pkh msg = + signer_operation path pkh msg Deterministic_nonce_request >>=? fun conn -> + Lwt_utils_unix.Socket.recv conn + (result_encoding Deterministic_nonce.Response.encoding) >>=? fun res -> + Lwt_unix.close conn >>= fun () -> + Lwt.return res + + let deterministic_nonce_hash path pkh msg = + signer_operation path pkh msg Deterministic_nonce_hash_request >>=? fun conn -> + Lwt_utils_unix.Socket.recv conn + (result_encoding Deterministic_nonce_hash.Response.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 @@ -108,6 +140,14 @@ module Make(P : sig parse (uri : sk_uri :> Uri.t) >>=? fun (path, pkh) -> sign ?watermark path pkh msg + let deterministic_nonce uri msg = + parse (uri : sk_uri :> Uri.t) >>=? fun (path, pkh) -> + deterministic_nonce path pkh msg + + let deterministic_nonce_hash uri msg = + parse (uri : sk_uri :> Uri.t) >>=? fun (path, pkh) -> + deterministic_nonce_hash path pkh msg + end module Tcp = struct @@ -154,6 +194,14 @@ module Make(P : sig parse (uri : sk_uri :> Uri.t) >>=? fun (path, pkh) -> sign ?watermark path pkh msg + let deterministic_nonce uri msg = + parse (uri : sk_uri :> Uri.t) >>=? fun (path, pkh) -> + deterministic_nonce path pkh msg + + let deterministic_nonce_hash uri msg = + parse (uri : sk_uri :> Uri.t) >>=? fun (path, pkh) -> + deterministic_nonce_hash path pkh msg + end end diff --git a/src/lib_signer_backends/unencrypted.ml b/src/lib_signer_backends/unencrypted.ml index eb8507d24..6909bfad9 100644 --- a/src/lib_signer_backends/unencrypted.ml +++ b/src/lib_signer_backends/unencrypted.ml @@ -66,3 +66,11 @@ let public_key_hash ?interactive pk_uri = let sign ?watermark sk_uri buf = secret_key sk_uri >>=? fun sk -> return (Signature.sign ?watermark sk buf) + +let deterministic_nonce sk_uri buf = + secret_key sk_uri >>=? fun sk -> + return (Signature.deterministic_nonce sk buf) + +let deterministic_nonce_hash sk_uri buf = + secret_key sk_uri >>=? fun sk -> + return (Signature.deterministic_nonce_hash sk buf) diff --git a/src/lib_signer_services/signer_messages.ml b/src/lib_signer_services/signer_messages.ml index 7804a568c..54e430779 100644 --- a/src/lib_signer_services/signer_messages.ml +++ b/src/lib_signer_services/signer_messages.ml @@ -23,35 +23,57 @@ (* *) (*****************************************************************************) +module type Authenticated_request = 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 + +module type Tag = sig + val tag: int +end + +module Make_authenticated_request(T: Tag) : Authenticated_request = struct + + type t = { + pkh: Signature.Public_key_hash.t ; + data: MBytes.t ; + signature: Signature.t option ; + } + + let to_sign ~pkh ~data = + let tag = MBytes.make 1 '0' in + MBytes.set_int8 tag 0 T.tag; + MBytes.concat "" + [ MBytes.of_string "\x04" ; + tag; + Signature.Public_key_hash.to_bytes pkh ; + data ] + + let encoding = + let open Data_encoding in + conv + (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) + (opt "signature" Signature.encoding)) + +end + module Sign = struct - module Request = 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_string "\x04" ; - Signature.Public_key_hash.to_bytes pkh ; - data ] - - let encoding = - let open Data_encoding in - conv - (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) - (opt "signature" Signature.encoding)) - - end + module Request = Make_authenticated_request (struct let tag = 1 end) module Response = struct @@ -64,6 +86,37 @@ module Sign = struct end +module Deterministic_nonce = struct + + module Request = Make_authenticated_request (struct let tag = 2 end) + + module Response = struct + + type t = MBytes.t + + let encoding = + Data_encoding.(obj1 (req "deterministic_nonce" bytes)) + + end + +end + +module Deterministic_nonce_hash = struct + + module Request = Make_authenticated_request (struct let tag = 3 end) + + module Response = struct + + type t = MBytes.t + + let encoding = + Data_encoding.(obj1 (req "deterministic_nonce_hash" bytes)) + + end + +end + + module Public_key = struct module Request = struct @@ -118,6 +171,8 @@ module Request = struct | Sign of Sign.Request.t | Public_key of Public_key.Request.t | Authorized_keys + | Deterministic_nonce of Deterministic_nonce.Request.t + | Deterministic_nonce_hash of Deterministic_nonce_hash.Request.t let encoding = let open Data_encoding in @@ -141,6 +196,20 @@ module Request = struct (obj1 (req "kind" (constant "authorized_keys"))) (function Authorized_keys -> Some () | _ -> None) (fun () -> Authorized_keys) ; + case (Tag 3) + ~title:"Deterministic_nonce" + (merge_objs + (obj1 (req "kind" (constant "deterministic_nonce"))) + Deterministic_nonce.Request.encoding) + (function Deterministic_nonce req -> Some ((), req) | _ -> None) + (fun ((), req) -> Deterministic_nonce req) ; + case (Tag 4) + ~title:"Deterministic_nonce_hash" + (merge_objs + (obj1 (req "kind" (constant "deterministic_nonce_hash"))) + Deterministic_nonce_hash.Request.encoding) + (function Deterministic_nonce_hash req -> Some ((), req) | _ -> None) + (fun ((), req) -> Deterministic_nonce_hash req) ; ] end diff --git a/src/lib_signer_services/signer_messages.mli b/src/lib_signer_services/signer_messages.mli index 931703b9a..8450214cf 100644 --- a/src/lib_signer_services/signer_messages.mli +++ b/src/lib_signer_services/signer_messages.mli @@ -23,20 +23,22 @@ (* *) (*****************************************************************************) +module type Authenticated_request = 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 + module Sign : sig - module Request : 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 + module Request : Authenticated_request module Response : sig type t = Signature.t @@ -45,6 +47,28 @@ module Sign : sig end +module Deterministic_nonce : sig + + module Request : Authenticated_request + + module Response : sig + type t = MBytes.t + val encoding : t Data_encoding.t + end + +end + +module Deterministic_nonce_hash : sig + + module Request : Authenticated_request + + module Response : sig + type t = MBytes.t + val encoding : t Data_encoding.t + end + +end + module Public_key : sig module Request : sig @@ -70,12 +94,15 @@ module Authorized_keys : sig end + module Request : sig type t = | Sign of Sign.Request.t | Public_key of Public_key.Request.t | Authorized_keys + | Deterministic_nonce of Deterministic_nonce.Request.t + | Deterministic_nonce_hash of Deterministic_nonce_hash.Request.t val encoding : t Data_encoding.t end diff --git a/src/lib_signer_services/signer_services.ml b/src/lib_signer_services/signer_services.ml index 622060734..902305673 100644 --- a/src/lib_signer_services/signer_services.ml +++ b/src/lib_signer_services/signer_services.ml @@ -23,17 +23,19 @@ (* *) (*****************************************************************************) + +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 + 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 @@ -41,6 +43,22 @@ let sign = ~output: Data_encoding.(obj1 (req "signature" Signature.encoding)) RPC_path.(root / "keys" /: Signature.Public_key_hash.rpc_arg) +let deterministic_nonce = + RPC_service.post_service + ~description: "Obtain some random data generated deterministically from some piece of data with a given remote key" + ~query + ~input: Data_encoding.bytes + ~output: Data_encoding.(obj1 (req "deterministic_nonce" bytes)) + RPC_path.(root / "keys" /: Signature.Public_key_hash.rpc_arg) + +let deterministic_nonce_hash = + RPC_service.post_service + ~description: "Obtain the hash of some random data generated deterministically from some piece of data with a given remote key" + ~query + ~input: Data_encoding.bytes + ~output: Data_encoding.(obj1 (req "deterministic_nonce_hash" bytes)) + RPC_path.(root / "keys" /: Signature.Public_key_hash.rpc_arg) + let public_key = RPC_service.get_service ~description: "Retrieve the public key of a given remote key" diff --git a/src/lib_signer_services/signer_services.mli b/src/lib_signer_services/signer_services.mli index 5ae10b060..d8b850e2f 100644 --- a/src/lib_signer_services/signer_services.mli +++ b/src/lib_signer_services/signer_services.mli @@ -27,6 +27,14 @@ val sign : ([ `POST ], unit, unit * Signature.Public_key_hash.t, Signature.t option, MBytes.t, Signature.t) RPC_service.t +val deterministic_nonce : + ([ `POST ], unit, unit * Signature.Public_key_hash.t, + Signature.t option, MBytes.t, MBytes.t) RPC_service.t + +val deterministic_nonce_hash : + ([ `POST ], unit, unit * Signature.Public_key_hash.t, + Signature.t option, MBytes.t, MBytes.t) RPC_service.t + val public_key : ([ `GET ], unit, unit * Signature.Public_key_hash.t, unit, unit, Signature.Public_key.t) RPC_service.t