diff --git a/keys.json b/keys.json new file mode 100644 index 00000000..2ec8a5e6 --- /dev/null +++ b/keys.json @@ -0,0 +1 @@ +{"version":"31:0:0","base_url":"http://localhost:3434/","currency":"KUDO","currency_specification":{"name":"euro","num_fractional_input_digits":2,"num_fractional_normal_digits":2,"num_fractional_trailing_zero_digits":2,"alt_unit_names":"{\"0\":\"€\",\"3\":\"k€\"}","common_amounts":[]},"stefan_abs":"KUDO:0.00","stefan_log":"KUDO:0.00","stefan_lin":0,"asset_type":"fiat","accounts":[],"wire_fees":{"x-taler-bank":[]},"wads":[],"rewards_allowed":false,"kyc_enabled":false,"disable_direct_deposit":false,"master_public_key":"SJ0NYND22VQP3MP7FM754RDX8HCKVWAXTHY9SQNBTPRJZ2SPM2S0","reserve_closing_delay":{"d_us":32756645000000},"hard_limits":[],"zero_limits":[],"denominations":[{"cipher":"RSA","denoms":[{"rsa_pub":"040000YGPE1C5Y99752NH0XYQMV9H9QYRXTSZXNX7RV17GA0048H3QFVXDE7JZNFJ06H1WRF2XBXQPB9HP8X3XWJHCA710Y361C8S7S0Z6JAH7TPB8AYG6729880MJYS91W6Z4GFPSDSC37DW90N412VGZ6KBAJDW8EKTWW7KVZ19TR2V74CHX6KARHQFHFW71M1699NP632AXER9X8W7E6M5HQFSRKKX9C411XEX9E53RTH3JYZ0QZMJF5DRW0MW0WMD2M25AVPJNMZTZ49NWXFAV5M8278RRDWSGYNRVRZ8QC0FY76ZM6HQRYB5AA9CCJPA8NQSWRQ80GN7P8GDWJK2037BX56W30KD9G64WHX22HZE2WSEJZ0XEJG581ZVXTKC6CRFBRTFK98J9BXV3GNB9XXVX8F04002","master_sig":"HTJGF9WNSB11Z2A9ZGH44929TG7PCV98DBTZG94SZV8P474XB0S3TE9W30XAAEYNTNVEFMKTHVK2X7S4BSX87DN6GVSJEDC05EFG03R","stamp_start":{"t_s":1771956512},"stamp_expire_withdraw":{"t_s":1803492512},"stamp_expire_deposit":{"t_s":1803492512},"stamp_expire_legal":{"t_s":1803492512},"lost":null}],"value":"KUDO:0.01","fee_withdraw":"KUDO:0.00","fee_deposit":"KUDO:0.00","fee_refresh":"KUDO:0.00","fee_refund":"KUDO:0.00"},{"cipher":"RSA","denoms":[{"rsa_pub":"040000WTPHV9A7MEHVQREK8DM5NK5RAWGBJDR11ZTD44J1NR15FVF49QGKTTTRJHNV1T30J528W96WEC2VW9S197KD1KS27BPMJY2QYS65SNC2ZCE7BSXBQTSXJCRDGC99P5QMXVMSKDJ9HZC7T9HP8A0NMBWHJD5HXYEB60A9DVDA9KT7G7VFE30G6MEAQHP3G718VYCYYKDCXXXG1ZYDNW086V87KSD2VVDG7FKK59T8PHEKPAXHYQE1ZK2ATSVM8RJ1KXGDRQ7HPVP1ED9VDMV31KHZTVP76XSYZ8DT38VRMGREAC9XVQBXPA5AZ6WXF1J42MXSX3BN5QWBGV47XT0M1EX6VWJ2ERM1NWJ1CAH4BTR9D6C1EZQ9VY8XT4FZBGQ5C712Y5GFTJZEV556XBCDQWWMJ904002","master_sig":"M3HXFNVA2Q5508DZ982G0BE93Y0DS8BNMRPBA0MV9Y2Y1FN519XB0ZAFDRNAM5Y9WD02PD4DW0P3646KQE5B63N5KCN2QRYEFS1ZY2G","stamp_start":{"t_s":1771956512},"stamp_expire_withdraw":{"t_s":1803492512},"stamp_expire_deposit":{"t_s":1803492512},"stamp_expire_legal":{"t_s":1803492512},"lost":null}],"value":"KUDO:0.02","fee_withdraw":"KUDO:0.00","fee_deposit":"KUDO:0.00","fee_refresh":"KUDO:0.00","fee_refund":"KUDO:0.00"}],"exchange_sig":"WMKRQD4YPV3ZMAGR74CDXETSXZ1KMAMTH5PWB1PC16Q768A4VX6B964VEWX29PFFRK8ER96YKDVPDGFATRE12TNYH12K8BY2CK0AA00","exchange_pub":"M03XWHRBKYGVS46TX33W2NCKBH8KMSTXP0N5PS4H3EDS3TB6KYQG","recoup":[],"global_fees":[{"start_date":{"t_s":0},"end_date":{"t_s":99999999},"history_fee":"KUDO:0.00","account_fee":"KUDO:0.00","purse_fee":"KUDO:0.00","history_expiration":{"d_us":9999999000000},"purse_account_limit":1,"purse_timeout":{"d_us":9999999000000},"master_sig":"291EH5PMTD5KCM35VPREXS7VY87RZXAZS0WMN7CFA1MH2G1H40YSAJZT72Q64EKD22F278AHK8R71QSV03YNRC56CMN1SJXPG11PP3G"}],"list_issue_date":{"t_s":1771956512},"auditors":[],"signkeys":[{"key":"M03XWHRBKYGVS46TX33W2NCKBH8KMSTXP0N5PS4H3EDS3TB6KYQG","stamp_start":{"t_s":1795540112},"stamp_expire":{"t_s":1797358112},"stamp_end":{"t_s":1827076112},"master_sig":"86FX5WY3H55NW5RQ03BMH662S673E5FKHGZ04VG165CEN2D6E92A643NCPJ3AGF1F440SCT1D80PW5KJE7Q3YB44B99KJEQWMRQ8C38"},{"key":"5TSCRN9PKQQ7ZCKV3F2BGW9A25MV8BZA2MCAFY5TTKCH8PCVBDPG","stamp_start":{"t_s":1799168912},"stamp_expire":{"t_s":1800986912},"stamp_end":{"t_s":1830704912},"master_sig":"67ZS3X61MQ7PADPM8PXHC07E60CZY83YDSYQATF9QE6KGHRN4PV53N3MH0MEGJKMW0AZ6KTJ8S32R4BFDQEZD84PHQW7H1XXVGXHM3R"},{"key":"F7PWEYX3BDQ69CC0JZHYJ26XD72S228FVMPAVC8BGSPJC3PKQB60","stamp_start":{"t_s":1786468112},"stamp_expire":{"t_s":1788286112},"stamp_end":{"t_s":1818004112},"master_sig":"HAJ6E51F1M0YDWAE2JWN47VZX0WFB8RQ41C3XHMRGA36DNPCX29WJK0H960KZ8AKG7GH0P0BYKQWXYYA9VQ8MN4TDCNQ0H490E50238"},{"key":"XZK0WFNZWVEW8FVVW81GHVT90WB9FZVX7RE35MAH0NJ9YDMWVD50","stamp_start":{"t_s":1777396112},"stamp_expire":{"t_s":1779214112},"stamp_end":{"t_s":1808932112},"master_sig":"HDW4B986MYHK8A2KZZS6ZA2X1JCCR8Y32XZBWE95ZXS9WDXRKFFPDZZ7TY81NXK5NGY6AHXEASVX4VDXG36KHFY19D06FEYHFSPTR0R"},{"key":"KTVX6FAEDR74F7XXY9TQNBR568CQ3YABZYN9E8PZ6617CFJQ58M0","stamp_start":{"t_s":1788282512},"stamp_expire":{"t_s":1790100512},"stamp_end":{"t_s":1819818512},"master_sig":"CM3WV5QQ9ZHMGQ572MS8W1216WMQTNXW5W6H926Q95YFE22S4EXE8190575C0C9WPD0X9B383V5Y7WJ6Q3JSQZ2CWCFW2XYZH9ZE61G"},{"key":"G0N9CJ8508T0J1XS20NAS14JD6CPT8Y2RH7E3TV7PAFC9S6AJBZ0","stamp_start":{"t_s":1782839312},"stamp_expire":{"t_s":1784657312},"stamp_end":{"t_s":1814375312},"master_sig":"YGBG48VC8AH3DDEZ2DMNVZG2H0RJ63J1G1PP62SAGSFMP6X1XA2P5V2BRM5R1FNCXDDD97121TG1G3NKR3Y4ZF425QC3YDKHZB72W3G"},{"key":"HVM04856V7FTZV9F7QHXG6F5E14CDAAYBCHFBM525GRS50ADF5DG","stamp_start":{"t_s":1797354512},"stamp_expire":{"t_s":1799172512},"stamp_end":{"t_s":1828890512},"master_sig":"68DTEAG19RB2CQPCAW5JFH1MKSKNMFAEYSE8WR768JAYVM8DXVDJSS1N91VJ27VV2TNF0HZM4TRKT1X0XX1MP19KJNNT6TGFSR34J0G"},{"key":"WZGDNY0P30PPWS5MHYNKFW7CH36Y84HGHD6GENZSGKPDSH5YFTPG","stamp_start":{"t_s":1771956512},"stamp_expire":{"t_s":1773770912},"stamp_end":{"t_s":1803492512},"master_sig":"Y97D86NJQ6M3SYYFE6KHXWDSRWPFH10YHGCFJKXR0ENDK9F7K1TGVPZR0KC4GFQA4ZCTPQSVYXSBM5X0EMWBHPPKHM8JV4DYS91MA3G"},{"key":"V1XCV9RNZH2VC36HJXR838C72X0FE9KQ0M62MWR75SDJAR8MN150","stamp_start":{"t_s":1793725712},"stamp_expire":{"t_s":1795543712},"stamp_end":{"t_s":1825261712},"master_sig":"R7QE402H0XQGZ18YN7XE6C16XPN8QSSSN5DG2N66AWVKJB77CAW5HACZ88ZTD1E8XXF3PJSJ4ZPEDY6DJCTKFSPC4J9WCW8JWD72620"},{"key":"H0EYJN13VHZMPAY8R10HYSWDKMWH709C99H8HG5A60P9RP8Y5QHG","stamp_start":{"t_s":1800983312},"stamp_expire":{"t_s":1802801312},"stamp_end":{"t_s":1832519312},"master_sig":"CMJMZJZY4AM973SAQ65S3SQSR508AGGRTQR86MRZBK3JT879QWK3E6HXBH5YK0FR343NBN8JKJ7SKZSKWM62ZRRN6AMAKF6WR8KWA0R"},{"key":"QGBWFDYMVSB4AQMC604AFWXYYW4JJ00NXDSM9NW8E09FRZEJ65ZG","stamp_start":{"t_s":1781024912},"stamp_expire":{"t_s":1782842912},"stamp_end":{"t_s":1812560912},"master_sig":"NZQYJ5HWRVGFWYP3NKKCKN2JRPCR2GWM7EM3Z2B41DMGS8SE1T906RP67731Z1XK8V3QKJHT9T5NHJ1REH3AC2E5B37GWPGSHEFNA28"},{"key":"6K080RCP803623ZR9BCVZVV6T8BN7EVYZREG5GTXYPB45JWMWXS0","stamp_start":{"t_s":1784653712},"stamp_expire":{"t_s":1786471712},"stamp_end":{"t_s":1816189712},"master_sig":"QGPXX9PB8V3NQGJK679Q0NGJV1F6NZ573C7V4W3MMZSDN02FG29CNP8KZRE5DNPJ0VZRP0V8TD2HW96N178ZVCGMN94917AWF5DQ01G"},{"key":"4GCS29QVAB895PT57TBREJ7Z2FEEQGQ39AAMM4C7TP8S01J9ZMW0","stamp_start":{"t_s":1790096912},"stamp_expire":{"t_s":1791914912},"stamp_end":{"t_s":1821632912},"master_sig":"RTNQVDAKKNGNS0EFC3BBVRZPN602A5724JW2V1AA1D83G442R8BVJWB3ESJZMPBDMA876F09AZR4CEWQ62Q7F46NN7ANQAQSJ5HAY3G"},{"key":"084TDXBFFJG9G6XA5DE2MT1TDHPTX8ZEFP2XWZCEF7KYY3V599T0","stamp_start":{"t_s":1791911312},"stamp_expire":{"t_s":1793729312},"stamp_end":{"t_s":1823447312},"master_sig":"D7KQ0JV2MA5T56JPQ6A5WH3XWGYDW9EERMTF1Q36XM3RRRNNNG7YQ4145SGYANXSQ6KZG5FX0BA0WXV4644SKEEFJ0FGYFJ0KXHEG2R"},{"key":"8BSSW879HRZR8K62F7Y76TZ0ZXTT0HBJ01Y1M93J8PHWKB6S8GHG","stamp_start":{"t_s":1779210512},"stamp_expire":{"t_s":1781028512},"stamp_end":{"t_s":1810746512},"master_sig":"KEBEZ37E8GYQ72H2MXZHW0G5E1V4T46J6X9TSYEYBXZVQ9DB42849EYE939PT61RPCGAP888Q1H12QRA29R0PK8GTGBC79H6BBZA03R"},{"key":"ZFNDDWYTZ3CBFJMGYDV0NK4GSVP989ARVNFKQ0X07Y6F0M7CJEG0","stamp_start":{"t_s":1775581712},"stamp_expire":{"t_s":1777399712},"stamp_end":{"t_s":1807117712},"master_sig":"ETF8E2YK7SNRGBE49PS5MSB9HHQS7900K33AQKGVAHP61EBANA2XY5TJRNNTM0YWNXJYD291QP0SMD5W8GMJ6340C2GPBF7466EV82R"},{"key":"DX5DEZJDKYASBW4MJBPH1JY4V02GVYZD2JYJC0595XQ49S9MVX5G","stamp_start":{"t_s":1773767312},"stamp_expire":{"t_s":1775585312},"stamp_end":{"t_s":1805303312},"master_sig":"75S35NQBA0FXMNA0PTGHAMHZZ9481B96NGVP5F9B3F9YT9J3HP5MD20B375DVZB895ZN6PSS3N3WPB506DAMYBSW6BBZ9JVMDQBCJ1R"},{"key":"Y767Q8H0XMNDRVWKX9WSZ65GQEZHR1FMESXX0NVQDD63R8KQ9D6G","stamp_start":{"t_s":1802797712},"stamp_expire":{"t_s":1804612112},"stamp_end":{"t_s":1834333712},"master_sig":"6J18XT2EBE31K4ZBNWM611VXN63ADQFYMWW93HCW8QXA4EXHYE875CNA8EYATDMYW35B977QSNAPQQE74ZSC5PY79HCY6BHBD7TGE10"}]} \ No newline at end of file diff --git a/src/http_management.ml b/src/http_management.ml index dd40ef66..a431f362 100644 --- a/src/http_management.ml +++ b/src/http_management.ml @@ -9,7 +9,7 @@ module Keys_get = struct Logs.info (fun m -> m "GET /management/keys/"); let (module Keys : Keys.S) = Vif.Server.device Devices.keys server in let res = - let v = Keys.make_future_keys_response () in + let* v = Keys.make_future_keys_response () in Api.encode jsont v in Respond.result res req diff --git a/src/keys.ml b/src/keys.ml index bb1b6b72..18ec76ad 100644 --- a/src/keys.ml +++ b/src/keys.ml @@ -13,7 +13,7 @@ module type S = sig val denominations : unit -> Denomination.t list result val find_future_signkey : eddsa_pub -> Api.FutureSignKey.t result val find_future_denomination : denom_hash -> Api.FutureDenom.t result - val make_future_keys_response : unit -> Api.FutureKeysResponse.t + val make_future_keys_response : unit -> Api.FutureKeysResponse.t result val certify_future_signkey : eddsa_pub -> Signatures.ExchangeSigningKeyValidity.t -> unit result @@ -68,6 +68,7 @@ module Make (Conn : Pg.CONN) : S = struct m "some signkeys found in database are missing from secmod, \ (unclean database/secmod state?)"); + Logs.debug (fun m -> m "found %d active signkey(s)" (List.length l)); l let denominations () = @@ -84,9 +85,12 @@ module Make (Conn : Pg.CONN) : S = struct m "some denominations found in database are missing from secmod, \ (unclean database/secmod state?)"); + Logs.debug (fun m -> + m "found %d active denomination(s)" (List.length l)); l let make_future_sk (pub, (start, expire)) = + Logs.debug (fun m -> m "make_future_sk: `%s`" (EddsaPublicKey.to_b32 pub)); let open Time in let stamp_start = Timestamp.of_absolute start in let stamp_expire = Timestamp.of_absolute expire in @@ -113,6 +117,9 @@ module Make (Conn : Pg.CONN) : S = struct | Some v -> v let make_future_dn (h_pub, (section_name, pub, start)) = + Logs.debug (fun m -> + m "make_future_dn: `%s`" + (B32.encode @@ Hash.DenominationHash.to_octets h_pub)); let open Time in let Config.Coin. { @@ -187,16 +194,37 @@ module Make (Conn : Pg.CONN) : S = struct Ok future_dn let make_future_keys_response () = - let future_signkeys = Sm_eddsa.keys () |> List.map make_future_sk in - let future_denoms = Sm_rsa.keys () |> List.map make_future_dn in - Api.FutureKeysResponse. - { - future_denoms; - future_signkeys; - master_pub= Config.Exchange.master_public_key; - denom_secmod_public_key= Sm_rsa.sm_pub; - signkey_secmod_public_key= Sm_eddsa.sm_pub; - } + let now = Timestamp.of_ptime @@ Ptime_clock.now () in + (* get keys from database to filter out keys already certified *) + let* sk_db_l = Pg.get_signkeys conn ~now |> unwrap_err_caqti in + let sk_ht = Hashtbl.create 0xff in + List.iter (fun sk -> Hashtbl.replace sk_ht sk.Signkey.pub ()) sk_db_l; + let future_signkeys = + Sm_eddsa.keys () + |> List.filter (fun (pub, _) -> not @@ Hashtbl.mem sk_ht pub) + |> List.map make_future_sk + in + let* dn_db_l = Pg.get_denominations conn () |> unwrap_err_caqti in + let dn_ht = Hashtbl.create 0xff in + List.iter (fun dn -> Hashtbl.replace dn_ht dn.Denomination.h_pub ()) dn_db_l; + let future_denoms = + Sm_rsa.keys () + |> List.filter (fun (h_pub, _) -> not @@ Hashtbl.mem dn_ht h_pub) + |> List.map make_future_dn + in + Logs.info (fun m -> + m "%d future signkey(s) and %d future denomination(s) to certify" + (List.length future_signkeys) + (List.length future_denoms)); + Ok + Api.FutureKeysResponse. + { + future_denoms; + future_signkeys; + master_pub= Config.Exchange.master_public_key; + denom_secmod_public_key= Sm_rsa.sm_pub; + signkey_secmod_public_key= Sm_eddsa.sm_pub; + } let sk_of_future_sk future_sk master_sig = let Api.FutureSignKey. @@ -257,8 +285,10 @@ module Make (Conn : Pg.CONN) : S = struct (* rebuild it *) let future_sk = make_future_sk (pub, (t1, t2)) in let sk = sk_of_future_sk future_sk master_sig in - let* () = Pg.insert_signkey conn sk |> unwrap_err_caqti in - Ok ()) + let+ () = Pg.insert_signkey conn sk |> unwrap_err_caqti in + Logs.info (fun m -> + m "certified signkey `%s`" (EddsaPublicKey.to_b32 sk.pub)); + ()) let certify_future_denomination h_pub master_sig = match Sm_rsa.find_key h_pub with @@ -272,8 +302,11 @@ module Make (Conn : Pg.CONN) : S = struct | None -> let future_dn = make_future_dn (h_pub, (section_name, pub, t1)) in let dn = dn_of_future_dn future_dn h_pub master_sig in - let* () = Pg.insert_denom conn dn |> unwrap_err_caqti in - Ok ()) + let+ () = Pg.insert_denom conn dn |> unwrap_err_caqti in + Logs.info (fun m -> + m "certified denomination `%s`" + (B32.encode @@ Hash.DenominationHash.to_octets dn.h_pub)); + ()) let revoke_signkey pub revoked_sig = let* opt = find_signkey pub in @@ -282,6 +315,7 @@ module Make (Conn : Pg.CONN) : S = struct let+ () = Pg.insert_signkey_revocation conn pub revoked_sig |> unwrap_err_caqti in + Logs.info (fun m -> m "revoked signkey `%s`" (EddsaPublicKey.to_b32 pub)); () let revoke_denomination h_pub revoked_sig = @@ -292,5 +326,8 @@ module Make (Conn : Pg.CONN) : S = struct Pg.insert_denomination_revocation conn dn.h_pub revoked_sig |> unwrap_err_caqti in + Logs.info (fun m -> + m "revoked denomination `%s`" + (B32.encode @@ Hash.DenominationHash.to_octets h_pub)); () end diff --git a/src/secmod_eddsa.ml b/src/secmod_eddsa.ml index 9aa95cd0..6cf9ac1e 100644 --- a/src/secmod_eddsa.ml +++ b/src/secmod_eddsa.ml @@ -57,11 +57,17 @@ let write_eddsa fpath priv = let write_key k = write_eddsa (key_fpath k) k.priv let delete_file fpath = - Log.debug (fun m -> m "(disabled) delete key file `%a`" Fpath.pp fpath); - (* TODO just to be safe~~ + (* check fpath just to be safe *) + let () = + let root = Fpath.v Cfg.key_dir in + if not @@ Fpath.is_rooted ~root fpath then + Fmt.failwith + "delete_file failure: file `%a` is not contained in secmod directory" + Fpath.pp fpath + in + Log.debug (fun m -> m "delete key file `%a`" Fpath.pp fpath); let+ () = Bos.OS.File.delete ~must_exist:true fpath |> unwrap_err_msg in -*) - Ok () + () let get_key_dir_contents dir = let* dir = Fpath.of_string dir |> unwrap_err_msg in @@ -70,7 +76,7 @@ let get_key_dir_contents dir = let+ l = Bos.OS.Dir.contents ~dotfiles:false ~rel:false dir |> unwrap_err_msg in - l + List.map Fpath.normalize l (* -- *) @@ -131,11 +137,7 @@ let load_key fpath = let load () = let* l = get_key_dir_contents Cfg.key_dir in - let l = - l - |> List.map Fpath.normalize - |> List.filter (fun fpath -> not @@ Fpath.equal fpath sm_key_fpath) - in + let l = List.filter (fun fpath -> not @@ Fpath.equal fpath sm_key_fpath) l in let* keys = list_map load_key l in match keys with | [] -> Ok None @@ -162,7 +164,7 @@ let init () = let now = TimeAbsolute.of_ptime (Ptime_clock.now ()) in let keys = List.of_seq @@ Hashtbl.to_seq_values t.ht in let new_keys = gen_additional_keys_until_lookahead ~now keys in - let () = List.iter (fun k -> Hashtbl.replace t.ht k.pub k) keys in + List.iter (fun k -> Hashtbl.replace t.ht k.pub k) new_keys; let+ () = list_iter write_key new_keys in t @@ -178,6 +180,7 @@ module Make () = struct let add t1 t2 = let k = gen_key t1 t2 in Hashtbl.replace t.ht k.pub k; + let+ () = write_key k in () let delete pub = @@ -206,7 +209,8 @@ module Make () = struct let revoke pub = let* k = find pub in let* () = delete pub in - add k.t1 k.t2; Ok () + let* () = add k.t1 k.t2 in + Ok () let conv = fun { priv= _; pub; t1; t2 } -> (pub, (t1, t2)) let keys () = Hashtbl.to_seq_values t.ht |> List.of_seq |> List.map conv diff --git a/src/secmod_rsa.ml b/src/secmod_rsa.ml index fef265f1..226afccb 100644 --- a/src/secmod_rsa.ml +++ b/src/secmod_rsa.ml @@ -100,11 +100,17 @@ let write_rsa fpath priv = let write_key k = write_rsa (key_fpath k) k.priv let delete_file fpath = - Log.debug (fun m -> m "(disabled) delete key file `%a`" Fpath.pp fpath); - (* TODO just to be safe~~ + (* check fpath just to be safe *) + let () = + let root = Fpath.v Cfg.key_dir in + if not @@ Fpath.is_rooted ~root fpath then + Fmt.failwith + "delete_file failure: file `%a` is not contained in secmod directory" + Fpath.pp fpath + in + Log.debug (fun m -> m "delete key file `%a`" Fpath.pp fpath); let+ () = Bos.OS.File.delete ~must_exist:true fpath |> unwrap_err_msg in -*) - Ok () + () let get_key_dir_contents dir_fpath = let* b = Bos.OS.Dir.create ~mode:0o700 dir_fpath |> unwrap_err_msg in @@ -112,7 +118,7 @@ let get_key_dir_contents dir_fpath = let+ l = Bos.OS.Dir.contents ~dotfiles:false ~rel:false dir_fpath |> unwrap_err_msg in - l + List.map Fpath.normalize l (* -- *) @@ -179,11 +185,7 @@ let load_key ~section_name fpath = let load_section section_name = let section_fpath = Fpath.(v Cfg.key_dir / section_name) in let* l = get_key_dir_contents section_fpath in - let l = - l - |> List.map Fpath.normalize - |> List.filter (fun fpath -> not @@ Fpath.equal fpath sm_key_fpath) - in + let l = List.filter (fun fpath -> not @@ Fpath.equal fpath sm_key_fpath) l in let* keys = list_map (load_key ~section_name) l in Ok keys @@ -224,7 +226,7 @@ let init () = Cfg.sections in let new_keys = List.concat new_keys_l in - let () = List.iter (fun k -> Hashtbl.replace t.ht k.h_pub k) new_keys in + List.iter (fun k -> Hashtbl.replace t.ht k.h_pub k) new_keys; let+ () = list_iter write_key new_keys in t @@ -252,6 +254,7 @@ module Make () = struct let add section_name t1 t2 = let k = gen_key ~section_name t1 t2 in Hashtbl.replace t.ht k.h_pub k; + let+ () = write_key k in () let sm_pub = t.sm_pub @@ -263,9 +266,11 @@ module Make () = struct data let revoke h_pub = + Log.debug (fun m -> + m "revoke `%s`" (DenominationHash.to_octets h_pub |> B32.encode)); let* k = find h_pub in let* () = delete h_pub in - add k.section_name k.t1 k.t2; + let* () = add k.section_name k.t1 k.t2 in Ok () let conv = diff --git a/src/util.ml b/src/util.ml index bf00cd53..07215a01 100644 --- a/src/util.ml +++ b/src/util.ml @@ -48,8 +48,13 @@ module Log_reporter = struct in { report } + let set_level_secmods lvl = + let secmod_srcs = [ Secmod_rsa.src; Secmod_eddsa.src ] in + List.iter (fun src -> Logs.Src.set_level src lvl) secmod_srcs; + () + let setup () = - (*Logs.Src.set_level Secmod_rsa.src (Some Logs.Debug);*) + (*set_level_secmods (Some Logs.Debug);*) let level = Some Logs.Info in Logs.set_level ~all:false level; Fmt_tty.setup_std_outputs ~style_renderer:`Ansi_tty ~utf_8:true (); diff --git a/test/offline_management.sh b/test/offline_management.sh index e8a22785..27e3815e 100755 --- a/test/offline_management.sh +++ b/test/offline_management.sh @@ -22,6 +22,25 @@ offline_tool sign \ offline_tool upload --input $b --url $url"/management/keys" echo "[OK] /management/keys" +offline_tool download --output $a --url $url"/keys" +rsa_pub=$(jq -r '.denominations[0].denoms[0].rsa_pub' $a) +offline_tool revoke-denom \ +--master_key $master_key \ +--output $b \ +--rsa \ +$rsa_pub +h_denom=$(dune exec offline -- hash64 $rsa_pub) +offline_tool upload --input $b --url $url"/management/denominations/"$h_denom"/revoke" +echo "[OK] /management/denominations/\$H_DENOM/revoke" + +pub=$(jq -r '.signkeys[0].key' $a) +offline_tool revoke-signkey \ +--master_key $master_key \ +--output $b \ +$pub +offline_tool upload --input $b --url $url"/management/signkeys/"$pub"/revoke" +echo "[OK] /management/signkeys/\$EXCHANGE_PUB/revoke" + offline_tool enable-auditor \ --master_key $master_key \ --output $b \ @@ -32,6 +51,8 @@ offline_tool enable-auditor \ offline_tool upload --input $b --url $url"/management/auditors" echo "[OK] /management/auditors" +# todo test disable auditor + offline_tool wire-fee \ --master_key $master_key \ --output $b \ @@ -56,3 +77,9 @@ offline_tool global-fees \ --purse_timeout 9999999 offline_tool upload --input $b --url $url"/management/global-fees" echo "[OK] /management/global-fees" + +# todo test enable wire +# todo test disable wire +# todo test drain +# todo test aml-officer +# todo test partners diff --git a/tools/offline.ml b/tools/offline.ml index 3991fb8a..7c1059b7 100644 --- a/tools/offline.ml +++ b/tools/offline.ml @@ -128,14 +128,54 @@ let sign_cmd = let revoke_denom_cmd = let doc = "Revoke denomination." in - let h_denom = - let doc = "hash of denomination public key" in + let is_rsa_pub = + let doc = + "interpret input string as a RSA public key (in Crockford-base32) \ + instead of a denomination hash" + in + Arg.(value & flag & info [ "rsa" ] ~doc) + in + let v = + let doc = "hash of denomination (or RSA public key if --rsa is set)" in Arg.(required & pos 0 (some string) None & info [] ~doc) in Cmd.make (Cmd.info "revoke-denom" ~doc) @@ - let+ output = output and+ master_key = master_key and+ h_denom = h_denom in - revoke_denom ~output ~master_key ~h_denom + let+ output = output + and+ master_key = master_key + and+ is_rsa_pub = is_rsa_pub + and+ v = v in + let res = + match is_rsa_pub with + | false -> Ok v + | true -> ( + match B32.decode v with + | Error e -> Error e + | Ok s -> + let h = Hash.DenominationHash.hash s in + let s = B32.encode (Hash.DenominationHash.to_octets h) in + Ok s) + in + match res with + | Error e -> Error e + | Ok h_denom -> revoke_denom ~output ~master_key ~h_denom + +(* just for tests... *) +let test_hash64_cmd = + let doc = + "Compute SHA-512, print output to stdout, input and output are \ + Crockford-base32 encoded" + in + let s = Arg.(required & pos 0 (some string) None & info []) in + Cmd.make (Cmd.info "hash64" ~doc) + @@ + let+ s = s in + match B32.decode s with + | Error e -> Error e + | Ok s -> + let h = Hash.DenominationHash.hash s in + let s = B32.encode (Hash.DenominationHash.to_octets h) in + Fmt.pr "%s@." s; Ok () let revoke_signkey_cmd = let doc = "Revoke signkey." in @@ -305,6 +345,7 @@ let cli = wire_fee_cmd; global_fees_cmd; drain_cmd; + test_hash64_cmd; ] let main () = Cmd.eval_result cli