From 780ea76d33dab0e4780d260b5a3506fa2e552fed Mon Sep 17 00:00:00 2001 From: swrup Date: Tue, 17 Feb 2026 13:23:25 +0100 Subject: [PATCH] JJ: Description from the destination commit: .. JJ: Description from source commit: . --- src/api.ml | 13 +++++ src/http_information.ml | 71 ++++++++------------------ src/http_management.ml | 109 ++++++---------------------------------- src/secmod.ml | 78 +++++++++++++--------------- src/signkey.ml | 1 + 5 files changed, 84 insertions(+), 188 deletions(-) diff --git a/src/api.ml b/src/api.ml index b92ff019..074149bc 100644 --- a/src/api.ml +++ b/src/api.ml @@ -922,6 +922,19 @@ module SignKey = struct master_sig: ExchangeSigningKeyValidity.t; } + (* TODO rm one of them *) + let of_signkey + Signkey. + { + pub; + stamp_start; + stamp_expire; + stamp_end; + master_sig; + revoked_sig= _; + } = + { key= pub; stamp_start; stamp_expire; stamp_end; master_sig } + let jsont = let make key stamp_start stamp_expire stamp_end master_sig = { key; stamp_start; stamp_expire; stamp_end; master_sig } diff --git a/src/http_information.ml b/src/http_information.ml index bbc53b20..17186d5a 100644 --- a/src/http_information.ml +++ b/src/http_information.ml @@ -41,7 +41,6 @@ let denomgroup_of_denomdata master_sig; revoked_sig= _; } = - let master_sig = match master_sig with None -> assert false | Some v -> v in let denoms = [ RsaDenom. @@ -112,92 +111,66 @@ let mk_keys ~db_conn (module Sm : Secmod.S) ~last_issue_date = let wallet_balance_limit_without_kyc = None in let hard_limits = [] in let zero_limits = [] in - let denom_data_l = - (* TODO sm-db *) + let dn_l = (*Pg.get_denominations db_conn |> unwrap_err_caqti *) - Sm.get_denoms_data () - in - let denom_data_l = + Sm.get_denominations () + |> (* reverse chronological order *) - List.sort - (fun a b -> Stdlib.compare b.Denomination.stamp_start a.stamp_start) - denom_data_l + List.sort (fun a b -> + Stdlib.compare b.Denomination.stamp_start a.stamp_start) in let list_issue_date = - match denom_data_l with - | [] -> Time.Timestamp.never - | v :: _ -> v.Denomination.stamp_start + match dn_l with + | [] -> Timestamp.never + | dn :: _ -> dn.Denomination.stamp_start in let denominations = - let open Denomination in (* if `?last_issue_date` query param does not exactly match the `stamp_start` of one of the denomination keys, all keys are returned *) + let open Denomination in let l = match last_issue_date with - | None -> denom_data_l + | None -> dn_l | Some last_issue_date -> ( match List.find_opt - (fun v -> - Time.Timestamp.compare v.stamp_start last_issue_date = 0) - denom_data_l + (fun v -> Timestamp.compare v.stamp_start last_issue_date = 0) + dn_l with - | None -> denom_data_l + | None -> dn_l | Some _ -> List.filter (fun v -> Time.Timestamp.compare v.stamp_start last_issue_date >= 0) - denom_data_l) + dn_l) in List.map denomgroup_of_denomdata l in let signkeys = - (* TODO sm-db - use database signkey data / verify secmod and database are in sync *) (* let now = Ptime_clock.now () |> Option.some in let+ signkey_data_l = Pg.get_active_signkeys db_conn ~now |> unwrap_err_caqti in*) - let signkey_data_l = Sm.get_signkeys_data () in - let signkey_data_l = - List.sort - (fun a b -> - let open Signkey in - Stdlib.compare b.stamp_start a.stamp_start) - signkey_data_l - in - List.filter_map - (fun Signkey. - { - pub; - stamp_start; - stamp_expire; - stamp_end; - master_sig; - revoked_sig= _; - } -> - match master_sig with - | None -> None - | Some master_sig -> - Some - SignKey. - { key= pub; stamp_start; stamp_expire; stamp_end; master_sig }) - signkey_data_l + Sm.get_signkeys () + |> List.sort (fun a b -> + let open Signkey in + Stdlib.compare b.stamp_start a.stamp_start) + |> List.map Api.SignKey.of_signkey in let exchange_pub = (* the eddsa pub key used to sign exchange_sig *) match signkeys with | [] -> Fmt.failwith "exchange has no active signkey" - | v :: _ -> v.SignKey.key + | sk :: _ -> sk.SignKey.key in let exchange_sig = (* Compact EdDSA signature (binary-only) over the contatentation of all of the master_sigs (in reverse chronological order by group) in the arrays under "denominations". *) let hc = - denom_data_l - |> List.filter_map (fun v -> v.Denomination.master_sig) + dn_l + |> List.map (fun dn -> dn.Denomination.master_sig) |> List.map Signatures.DenominationKeyValidity.to_octets |> String.concat "" |> Hash.H64.hash diff --git a/src/http_management.ml b/src/http_management.ml index 9d79864a..72abe7e1 100644 --- a/src/http_management.ml +++ b/src/http_management.ml @@ -3,93 +3,12 @@ open Api open Hash module Keys_get = struct - let mk_future_denom (module Sm : Secmod.S) ~section_name - ({ - pub; - value; - stamp_start; - stamp_expire_withdraw; - stamp_expire_deposit; - stamp_expire_legal; - fee_withdraw; - fee_deposit; - fee_refresh; - fee_refund; - age_mask; - h_pub; - master_sig= _; - revoked_sig= _; - } : - Denomination.t) = - let denom_pub = - DenominationKey.of_rsa RsaDenominationKey.{ age_mask; rsa_pub= pub } - in - let denom_secmod_sig = - let open Signatures.DenominationKeyAnnouncement in - let h_denom_pub = h_pub in - let h_section_name = Hash.Cstring.H64.hash section_name in - let anchor_time = stamp_start in - let duration_withdraw = - Timestamp.diff stamp_start stamp_expire_withdraw - in - sign_f ~f:Sm.sign_with_sm_key - { h_denom_pub; h_section_name; anchor_time; duration_withdraw } - in - FutureDenom. - { - section_name; - value; - stamp_start; - stamp_expire_withdraw; - stamp_expire_deposit; - stamp_expire_legal; - denom_pub; - fee_withdraw; - fee_deposit; - fee_refresh; - fee_refund; - denom_secmod_sig; - } - - let mk_future_signkey (module Sm : Secmod.S) - ({ - pub; - stamp_start; - stamp_expire; - stamp_end; - master_sig= _; - revoked_sig= _; - } : - Signkey.t) = - let signkey_secmod_sig = - let open Signatures.SigningKeyAnnouncement in - let exchange_pub = pub in - let anchor_time = stamp_start in - let duration = Timestamp.diff stamp_start stamp_expire in - sign_f ~f:Sm.sign_with_sm_key { exchange_pub; anchor_time; duration } - in - FutureSignKey. - { key= pub; stamp_start; stamp_expire; stamp_end; signkey_secmod_sig } - let mk_future_keys_response (module Sm : Secmod.S) = - let future_signkeys = - Sm.get_signkeys_data () - |> List.filter (fun k -> Option.is_none k.Signkey.master_sig) - |> List.map (fun signkey -> mk_future_signkey (module Sm) signkey) - in - let future_denoms = - Sm.get_denoms_data () - |> List.filter (fun k -> Option.is_none k.Denomination.master_sig) - |> List.map (fun dn_data -> - let opt = Sm.find_denom_section_name dn_data.Denomination.h_pub in - match opt with - | None -> Fmt.failwith "section_name not found." - | Some section_name -> - mk_future_denom (module Sm) ~section_name dn_data) - in + let future_signkeys = Sm.get_future_signkeys () in + let future_denoms = Sm.get_future_denominations () in let master_pub = Config.Exchange.master_public_key in - let denom_secmod_public_key = Sm.get_sm_key_pub () in - let signkey_secmod_public_key = Sm.get_sm_key_pub () in + let denom_secmod_public_key = Sm.sm_pubkey in + let signkey_secmod_public_key = Sm.sm_pubkey in FutureKeysResponse. { future_denoms; @@ -144,7 +63,7 @@ module Keys_post = struct let verify_signkey_signature (module Sm : Secmod.S) SignKeySignature.{ key; master_sig } = let* signkey = - match Sm.find_signkey_data key with + match Sm.find_signkey key with | None -> Fmt.error "404 not found, One of the keys for which a signature was provided \ @@ -170,18 +89,18 @@ module Keys_post = struct let do_ ~db_conn:_ (module Sm : Secmod.S) MasterSignatures.{ denom_sigs; signkey_sigs } = let* () = - signkey_sigs - |> List.map (fun SignKeySignature.{ key; master_sig } -> - (key, master_sig)) - |> Sm.add_signkey_master_signatures + list_iter + (fun SignKeySignature.{ key; master_sig } -> + Sm.certify_future_signkey key master_sig) + signkey_sigs in let* () = - denom_sigs - |> List.map (fun DenomSignature.{ h_denom_pub; master_sig } -> - (h_denom_pub, master_sig)) - |> Sm.add_denom_master_signatures + list_iter + (fun DenomSignature.{ h_denom_pub; master_sig } -> + Sm.certify_future_denomination h_denom_pub master_sig) + denom_sigs in - let* () = Sm.store () in + let* () = Sm.save () in Ok () let jsont = MasterSignatures.jsont diff --git a/src/secmod.ml b/src/secmod.ml index b61f2f5e..39c4374b 100644 --- a/src/secmod.ml +++ b/src/secmod.ml @@ -48,7 +48,8 @@ module Make (Conn : Pg.CONN) = struct type dn = Denomination.t type future_dn = Api.FutureDenom.t - (* TODO use lock! *) + (* TODO ! use lock *) + (* not sure what to do with coin section_name, rm if possible *) type t = { sm_key: eddsa_priv; sm_pubkey: eddsa_pub; @@ -63,24 +64,25 @@ module Make (Conn : Pg.CONN) = struct dn_section_name_ht: (denom_hash, string) Hashtbl.t; } - let database_find_sk conn fname pub = + let sm_key_fname = Fpath.(Config.secrets_dir / "sm_key") + let sk_key_fname i = Fpath.(Config.secrets_dir / Fmt.str "sk_%d" i) + + let dn_key_fname section_name = + Fpath.(Config.secrets_dir / Fmt.str "dn_%s" section_name) + + let database_find_sk conn pub = let* opt = Pg.find_signkey conn pub |> unwrap_err_caqti in match opt with | None -> - Fmt.error - "load_signkey error, no associated data found in database for \ - signkey `%s`." - (Fpath.to_string fname) + Fmt.error "secmod failure: a signkey could not be found in database" | Some sk_data -> Ok sk_data - let database_find_dn conn ~section_name h_pub = + let database_find_dn conn h_pub = let* opt = Pg.find_denom conn h_pub |> unwrap_err_caqti in match opt with | None -> Fmt.error - "load_denom error no associated metadata found in database for \ - denomination `%s`." - section_name + "secmod failure: a denomination could not be found in database" | Some dn_data -> Ok dn_data (* TODO clean up *) @@ -88,18 +90,10 @@ module Make (Conn : Pg.CONN) = struct let error_invalid_state = Fmt.error "secmod load error: invalid store state." in - let* sm_key = Data_file.read_eddsa Fpath.(Config.secrets_dir / "sk_sm") in + let* sm_key = Data_file.read_eddsa sm_key_fname in let* sk_keys = - let l = - List.init 1 (fun i -> Fpath.(Config.secrets_dir / Fmt.str "sk_%d" i)) - in - let* l = - list_map - (fun fname -> - let+ opt = Data_file.read_eddsa fname in - Option.map (fun priv -> (fname, priv)) opt) - l - in + let l = List.init 1 sk_key_fname in + let* l = list_map (fun fname -> Data_file.read_eddsa fname) l in match opt_list l with Error () -> error_invalid_state | Ok opt -> Ok opt in let* dn_keys = @@ -108,8 +102,7 @@ module Make (Conn : Pg.CONN) = struct list_map (fun coin -> let section_name = coin.section_name in - let fname = Fpath.(Config.secrets_dir / section_name) in - let+ opt = Data_file.read_rsa fname in + let+ opt = Data_file.read_rsa (dn_key_fname section_name) in Option.map (fun priv -> (section_name, priv)) opt) all_coins in @@ -125,9 +118,9 @@ module Make (Conn : Pg.CONN) = struct (* sk *) let* l = list_map - (fun (fname, priv) -> + (fun priv -> let pub = EddsaPrivateKey.pub_of_priv priv in - let+ sk = database_find_sk conn fname pub in + let+ sk = database_find_sk conn pub in ((pub, sk), (pub, priv))) sk_keys in @@ -136,6 +129,7 @@ module Make (Conn : Pg.CONN) = struct (list_to_ht sk_l, list_to_ht priv_l) in (* dn *) + let dn_section_name_ht = Hashtbl.create 0xff in let* l = list_map (fun (section_name, priv) -> @@ -145,15 +139,18 @@ module Make (Conn : Pg.CONN) = struct |> RsaPublicKey.to_octets |> DenominationHash.hash in - let+ dn = database_find_dn conn ~section_name h_pub in + + (* fill dn_section_name_ht *) + Hashtbl.replace dn_section_name_ht h_pub section_name; + + let+ dn = database_find_dn conn h_pub in ((h_pub, dn), (h_pub, priv))) dn_keys in let dn_ht, dn_key_ht = - let dn_l, priv_l = List.split l in - (list_to_ht dn_l, list_to_ht priv_l) + match List.split l with l1, l2 -> (list_to_ht l1, list_to_ht l2) in - (* future keys are not stored (until they are signed) + (* future keys are not stored anywhere until they are certified with a master_sig so we don't have any future key to load *) let t = { @@ -167,7 +164,7 @@ module Make (Conn : Pg.CONN) = struct future_dn_ht= Hashtbl.create 0xff; future_sk_key_ht= Hashtbl.create 0xff; future_dn_key_ht= Hashtbl.create 0xff; - dn_section_name_ht= Hashtbl.create 0xff; + dn_section_name_ht; } in Ok (Some t) @@ -216,17 +213,16 @@ module Make (Conn : Pg.CONN) = struct age_restricted= _; } = assert (cipher = `RSA); - let open Time in - let start = Absolute.of_ptime (Ptime_clock.now ()) in + let start = Time.Absolute.of_ptime (Ptime_clock.now ()) in let stamp_start = Timestamp.of_absolute start in let stamp_expire_withdraw = - Timestamp.of_absolute @@ Absolute.add start duration_withdraw + Timestamp.of_absolute @@ Time.Absolute.add start duration_withdraw in let stamp_expire_deposit = - Timestamp.of_absolute @@ Absolute.add start duration_spend + Timestamp.of_absolute @@ Time.Absolute.add start duration_spend in let stamp_expire_legal = - Timestamp.of_absolute @@ Absolute.add start duration_legal + Timestamp.of_absolute @@ Time.Absolute.add start duration_legal in let priv, pub = RsaPrivateKey.generate ~bits:rsa_keysize () in let open Api in @@ -453,16 +449,11 @@ module Make (Conn : Pg.CONN) = struct Ok () let save () = - let* () = - let fname = Fpath.(Config.secrets_dir / "sk_sm") in - Data_file.write_eddsa fname t.sm_key - in + let* () = Data_file.write_eddsa sm_key_fname t.sm_key in let* () = Hashtbl.to_seq_values t.sk_key_ht |> List.of_seq - |> List.mapi (fun i priv -> - let fname = Fpath.(Config.secrets_dir / Fmt.str "sk_%d" i) in - Data_file.write_eddsa fname priv) + |> List.mapi (fun i priv -> Data_file.write_eddsa (sk_key_fname i) priv) |> list_iter Fun.id in let* () = @@ -474,8 +465,7 @@ module Make (Conn : Pg.CONN) = struct | None -> Error "invalid state, section_name not found" | Some s -> Ok s in - let fname = Fpath.(Config.secrets_dir / section_name) in - Data_file.write_rsa fname priv) + Data_file.write_rsa (dn_key_fname section_name) priv) in Logs.info (fun m -> m "saved secmod private keys data"); Ok () diff --git a/src/signkey.ml b/src/signkey.ml index 611b894c..a710aee6 100644 --- a/src/signkey.ml +++ b/src/signkey.ml @@ -1,5 +1,6 @@ open Crypto +(* TODO replace by Api.SignKey.t instead? (no revoked_sig) *) type t = { pub: eddsa_pub; stamp_start: Timestamp.t;