From fa218379479bfa9d3d65974236326412b51c3e84 Mon Sep 17 00:00:00 2001 From: swrup Date: Sat, 6 Dec 2025 20:50:29 +0100 Subject: [PATCH] verify MasterSignatures --- src/api.ml | 5 ++ src/api_sig.ml | 2 +- src/devices.ml | 1 + src/management.ml | 140 ++++++++++++++++++++++++++++++++++++++----- src/mte.ml | 6 +- tools/offline_sig.ml | 11 +--- 6 files changed, 139 insertions(+), 26 deletions(-) diff --git a/src/api.ml b/src/api.ml index 1422963f..0e77a541 100644 --- a/src/api.ml +++ b/src/api.ml @@ -69,10 +69,15 @@ module HashCode : sig type t val hash : string -> t + val to_octets : t -> string val jsont : t Jsont.t end = struct type t = B32.t + (* TODO rm + for convertion to DenominationHash *) + let to_octets s = s + let hash s = let open Digestif.SHA512 in s |> digest_string |> to_raw_string diff --git a/src/api_sig.ml b/src/api_sig.ml index b0ab5107..642369a5 100644 --- a/src/api_sig.ml +++ b/src/api_sig.ml @@ -193,7 +193,7 @@ module ExchangeSigningKeyValidityPS = struct type r = { start: TimeAbsoluteNBO.t; expire: TimeAbsoluteNBO.t; - end_: TimeAbsoluteNBO.t; (* "end" renamed to end_ *) + end_: TimeAbsoluteNBO.t; signkey_pub: ExchangePublicKeyP.t; } diff --git a/src/devices.ml b/src/devices.ml index 34538354..440d7545 100644 --- a/src/devices.ml +++ b/src/devices.ml @@ -85,6 +85,7 @@ end module Secmod_denom = struct type t = { sm_key: Signkey.t; + (* TODO rename *) keys: Denomination.t list; } diff --git a/src/management.ml b/src/management.ml index 92b53def..759d64af 100644 --- a/src/management.ml +++ b/src/management.ml @@ -65,24 +65,24 @@ let mk_future_signkey ~sm_signkey_priv FutureSignKey. { key= pub; stamp_start; stamp_expire; stamp_end; signkey_secmod_sig } -let mk_future_keys_response (secmod_signkey : Secmod_signkey.t) - (secmod_denom : Secmod_denom.t) = +let mk_future_keys_response ~(sm_signkey : Secmod_signkey.t) + ~(sm_denom : Secmod_denom.t) = let future_denoms = - secmod_denom.keys + sm_denom.keys |> List.filter (fun k -> Option.is_none k.Denomination.master_sig) |> List.map (fun denom -> - mk_future_denom ~sm_denom_priv:secmod_denom.sm_key.Signkey.priv denom) + mk_future_denom ~sm_denom_priv:sm_denom.sm_key.Signkey.priv denom) in let future_signkeys = - secmod_signkey.keys + sm_signkey.keys |> List.filter (fun k -> Option.is_none k.Signkey.master_sig) |> List.map (fun signkey -> - mk_future_signkey ~sm_signkey_priv:secmod_signkey.sm_key.Signkey.priv + mk_future_signkey ~sm_signkey_priv:sm_signkey.sm_key.Signkey.priv signkey) in let master_pub = Config.Exchange.master_public_key in - let denom_secmod_public_key = secmod_denom.sm_key.pub in - let signkey_secmod_public_key = secmod_signkey.sm_key.pub in + let denom_secmod_public_key = sm_denom.sm_key.pub in + let signkey_secmod_public_key = sm_signkey.sm_key.pub in FutureKeysResponse. { future_denoms; @@ -92,13 +92,125 @@ let mk_future_keys_response (secmod_signkey : Secmod_signkey.t) signkey_secmod_public_key; } -let keys_get req server _env = +let respond_with_plain_text_error ?status e req = + let open Vif.Response in + let open Syntax in + let status = Option.value ~default:`Bad_request status in + let* () = add ~field:"content-type" "text/plain; charset=utf-8" in + let* () = with_string req e in + respond status + +let respond_with_ok_json content req = let open Vif.Response in let open Syntax in - let secmod_signkey = Vif.Server.device Devices.secmod_signkey server in - let secmod_denom = Vif.Server.device Devices.secmod_denom server in - let v = mk_future_keys_response secmod_signkey secmod_denom in - let s = Api.encode_exn Api.FutureKeysResponse.jsont v in - let* () = with_string req s in let* () = add ~field:"content-type" "application/json" in + let* () = with_string req content in respond `OK + +let respond_with_res res req = + match res with + | Error err -> respond_with_plain_text_error err req + | Ok content -> respond_with_ok_json content req + +let keys_get req server _env = + let sm_signkey = Vif.Server.device Devices.secmod_signkey server in + let sm_denom = Vif.Server.device Devices.secmod_denom server in + let res = + let v = mk_future_keys_response ~sm_signkey ~sm_denom in + let s = Api.encode_exn Api.FutureKeysResponse.jsont v in + Ok s + in + respond_with_res res req + +(* - ** - *) + +let verify_denom_signature ~sm_denom DenomSignature.{ h_denom_pub; master_sig } + = + let open Syntax in + let denom_hash = + Bin_type.DenominationHash.of_octets (HashCode.to_octets h_denom_pub) + in + let* denom = + let opt = + List.find_opt + (fun (denom : Denomination.t) -> denom.h_pub = denom_hash) + sm_denom.Secmod_denom.keys + in + match opt with + | None -> + Fmt.error + "404 not found, One of the keys for which a signature was provided \ + is unknown to the exchange." + | Some denom -> Ok denom + in + let open Api_sig.DenominationKeyValidityPS in + let r : r = + { + master= Config.master_public_key; + start= denom.stamp_start; + expire_withdraw= denom.stamp_expire_withdraw; + expire_spend= denom.stamp_expire_deposit; + expire_legal= denom.stamp_expire_legal; + value= denom.value; + fee_withdraw= denom.fee_withdraw; + fee_deposit= denom.fee_deposit; + fee_refresh= denom.fee_refresh; + denom_hash; + } + in + verify ~key:Config.master_public_key master_sig r + +let verify_signkey_signature ~sm_signkey SignKeySignature.{ key; master_sig } = + let open Syntax in + let* signkey = + let opt = + List.find_opt + (fun (signkey : Signkey.t) -> signkey.pub = key) + sm_signkey.Secmod_signkey.keys + in + match opt with + | None -> + Fmt.error + "404 not found, One of the keys for which a signature was provided \ + is unknown to the exchange." + | Some signkey -> Ok signkey + in + let open Api_sig.ExchangeSigningKeyValidityPS in + let r : r = + { + start= signkey.stamp_start; + expire= signkey.stamp_expire; + end_= signkey.stamp_end; + signkey_pub= signkey.pub; + } + in + verify ~key:Config.master_public_key master_sig r + +let verify_master_signatures ~sm_signkey ~sm_denom + MasterSignatures.{ denom_sigs; signkey_sigs } = + let open Syntax in + let* () = list_iter (verify_denom_signature ~sm_denom) denom_sigs in + let* () = list_iter (verify_signkey_signature ~sm_signkey) signkey_sigs in + Ok () + +let store_master_signatures _ = Ok () + +let keys_post req server _env = + let sm_signkey = Vif.Server.device Devices.secmod_signkey server in + let sm_denom = Vif.Server.device Devices.secmod_denom server in + let res = + let open Syntax in + let* master_signatures = + match Vif.Request.of_json req with + | Ok (v : MasterSignatures.t) -> Ok v + | Error (`Msg msg) -> + Logs.err (fun m -> m "Invalid JSON: %s" msg); + Error msg + in + let* () = + verify_master_signatures ~sm_signkey ~sm_denom master_signatures + in + let* () = store_master_signatures () in + Ok "" + in + respond_with_res res req diff --git a/src/mte.ml b/src/mte.ml index 4f660718..51826093 100644 --- a/src/mte.ml +++ b/src/mte.ml @@ -23,12 +23,16 @@ let hello req _server _env = let routes = let open Vif.Uri in let open Vif.Route in - (*let open Vif.Type in*) + let open Vif.Type in + let open Api in + let post jsont = post (json_encoding jsont) in [ get (rel /?? nil) --> hello; get (rel / "terms" /?? nil) --> Static.terms; get (rel / "privacy" /?? nil) --> Static.privacy; get (rel / "management" / "keys" /?? nil) --> Management.keys_get; + post MasterSignatures.jsont (rel / "management" / "keys" /?? nil) + --> Management.keys_post; ] let () = diff --git a/tools/offline_sig.ml b/tools/offline_sig.ml index 1703c1a6..e39c7411 100644 --- a/tools/offline_sig.ml +++ b/tools/offline_sig.ml @@ -16,7 +16,6 @@ let denom_signature ~master_key fee_deposit; fee_refresh; fee_refund= _; - (* TODO check sigs *) denom_secmod_sig= _; } = let octets = DenominationKey.to_octets denom_pub in @@ -43,14 +42,7 @@ let denom_signature ~master_key let signkey_signature ~master_key FutureSignKey. - { - key; - stamp_start; - stamp_expire; - stamp_end; - (* TODO check sigs *) - signkey_secmod_sig= _; - } = + { key; stamp_start; stamp_expire; stamp_end; signkey_secmod_sig= _ } = let master_sig = let open Api_sig.ExchangeSigningKeyValidityPS in sign ~key:master_key @@ -68,7 +60,6 @@ let make_master_signatures ~master_key { future_denoms; future_signkeys; - (* TODO check sigs *) master_pub= _; denom_secmod_public_key= _; signkey_secmod_public_key= _;