diff --git a/src/base_32.ml b/src/b32.ml similarity index 97% rename from src/base_32.ml rename to src/b32.ml index bbc96e96..29e73239 100644 --- a/src/base_32.ml +++ b/src/b32.ml @@ -7,6 +7,8 @@ - checksum is not allowed *) (* 'I' 'L' 'O' 'U' excluded *) +type t = string + let alphabet = Base32.make_alphabet "0123456789ABCDEFGHJKMNPQRSTVWXYZ" let encode s = Base32.encode_string ~alphabet s diff --git a/src/config.ml b/src/config.ml index 1be79a0a..d9303674 100644 --- a/src/config.ml +++ b/src/config.ml @@ -22,26 +22,17 @@ module Exchange = struct let enable_kyc = `NO end -type currency = { - enabled: [ `YES | `NO ]; - code: string; - name: string; - fractional_input_digits: int; - fractional_normal_digits: int; - fractional_trailing_zero_digits: int; - alt_unit_names: (int * string) list; -} - let currency_eur = - { - enabled= `NO; - code= "EUR"; - name= "euro"; - fractional_input_digits= 2; - fractional_normal_digits= 2; - fractional_trailing_zero_digits= 2; - alt_unit_names= [ (0, "E"); (3, "kE") ]; - } + Types.Config_types.Currency. + { + enabled= `NO; + code= "EUR"; + name= "euro"; + fractional_input_digits= 2; + fractional_normal_digits= 2; + fractional_trailing_zero_digits= 2; + alt_unit_names= [ (0, "E"); (3, "kE") ]; + } module Secmod_rsa = struct let lookahead_sign = 9999999 @@ -57,31 +48,21 @@ module Secmod_eddsa = struct let key_dir = Fpath.(v "eddsa") end -type coin = { - value: Amount.t; - duration_withdraw: int; - duration_spend: int; - duration_legal: int; - fee_withdraw: Amount.t; - fee_deposit: Amount.t; - fee_refresh: Amount.t; - fee_refund: Amount.t; - cipher: [ (* `CS |*) `RSA ]; - rsa_keysize: int option (*only if `RSA *); - age_restricted: [ (*`YES|*) `NO ]; -} +let coin_kudo_1 = + Types.Config_types.Coin. + { + value= amount "EUR:0.01"; + duration_withdraw= 999999; + duration_spend= 999999; + duration_legal= 999999; + fee_withdraw= amount "EUR:0.00"; + fee_deposit= amount "EUR:0.00"; + fee_refresh= amount "EUR:0.00"; + fee_refund= amount "EUR:0.00"; + cipher= `RSA; + rsa_keysize= Some 2048; + age_restricted= `NO; + } -let coin_kudo = - { - value= amount "EUR:0.01"; - duration_withdraw= 999999; - duration_spend= 999999; - duration_legal= 999999; - fee_withdraw= amount "EUR:0.00"; - fee_deposit= amount "EUR:0.00"; - fee_refresh= amount "EUR:0.00"; - fee_refund= amount "EUR:0.00"; - cipher= `RSA; - rsa_keysize= Some 2048; - age_restricted= `NO; - } +let coin_kudo_2 = { coin_kudo_1 with value= amount "EUR:0.02" } +let coins = [ coin_kudo_1; coin_kudo_2 ] diff --git a/src/dune b/src/dune index 14dee822..10d30192 100644 --- a/src/dune +++ b/src/dune @@ -7,10 +7,10 @@ (library (name mte) (wrapped false) - (modules :standard \ mte base_32 amount) + (modules :standard \ mte b32 amount) (libraries amount - base_32 + b32 ; include ; @@ -25,8 +25,8 @@ cohttp)) (library ; crockford base32 - (name base_32) - (modules base_32) + (name b32) + (modules b32) (libraries base32)) (library diff --git a/src/management.ml b/src/management.ml deleted file mode 100644 index bae61bef..00000000 --- a/src/management.ml +++ /dev/null @@ -1,48 +0,0 @@ -(* TODO - - https://docs.taler.net/taler-exchange-manual.html#offline-signing-setup-key-maintenance-and-tear-down - - The exchange HTTP service must be running before you can complete the following offline signing procedure. Note that when an exchange is running without offline keys its not fully operational. To make the exchange HTTP service fully operational, the following steps involving the offline signing machine must be completed: - - 1) The public keys of various online keys used by the exchange service are exported via a management HTTP API. - - 2) The offline signing system validates this request and signs it. - Additionally, the offline signing system signs policy messages to configure the exchange’s bank - accounts and associated fees. - - 3) The messages generated by the offline signing system are uploaded via the management API - of the exchange HTTP service. -*) - -(* - - generate (pub&priv) key for online signing key - - generate (pub&priv) key for denomination(s) - - implement `GET /management/keys` - - implement `POST /management/keys` - - offline tool do: GET -> sign -> POST - - now we should have a server with valid keys signed by the master offline key *) -(* implement secmod / crytpo stuff as a vif device *) - -(* https://docs.taler.net/core/api-common.html#cryptographic-primitives - - All elliptic curve operations are on Curve25519. - Public and private keys are thus 32 bytes, and signatures 64 bytes. - For hashing, including HKDFs, Taler uses 512-bit hash codes (64 bytes). *) - -type key = - | Eddsa of Mirage_crypto_ec.Ed25519.(priv * pub) - | Rsa of Mirage_crypto_pk.Rsa.(priv * pub) - -let eddsa_online_key_device = - let finally _key = () in - Vif.Device.v ~name:"eddsa_online_key" ~finally [] @@ fun () -> - (* [Mirage_crypto_rng_miou_unix.(initialize (module Pfortuna))] is already done by [Vif.run] *) - Eddsa (Mirage_crypto_ec.Ed25519.generate ()) - -let rsa_denomination_key_device = - let finally _key = () in - Vif.Device.v ~name:"rsa_denomination_key" ~finally [] @@ fun () -> - let open Mirage_crypto_pk.Rsa in - let rsa_keysize = 2048 in - let priv = generate ~bits:rsa_keysize () in - Rsa (priv, pub_of_priv priv) diff --git a/src/mte.ml b/src/mte.ml index 88b4085d..7b566308 100644 --- a/src/mte.ml +++ b/src/mte.ml @@ -125,8 +125,8 @@ let () = let devices = Vif.Devices. [ - Management.eddsa_online_key_device; - Management.rsa_denomination_key_device; + Secmod_keys.signkey_device; Secmod_keys.denom_device; + Secmod_denom.denom_device; ] in let middlewares = Vif.Middlewares.[] in diff --git a/src/secmod_denom.ml b/src/secmod_denom.ml new file mode 100644 index 00000000..e95cd769 --- /dev/null +++ b/src/secmod_denom.ml @@ -0,0 +1,23 @@ +type rsa = { + coin: Types.Config_types.Coin.t; + pub: Types.RsaPublicKey.t; + sign: string -> string; +} + +let hash_pub _pub = "todo public key converted to Crockford Base32" + +let make_rsa (coin : Types.Config_types.Coin.t) = + assert (coin.cipher = `RSA); + assert (Option.is_some coin.rsa_keysize); + let rsa_keysize = coin.rsa_keysize |> Option.get in + let open Mirage_crypto_pk.Rsa in + let priv = generate ~bits:rsa_keysize () in + let pub = pub_of_priv priv in + let sign = decrypt ~crt_hardening:true ~mask:`Yes ~key:priv in + { coin; pub; sign } + +let denom_device = + let finally _key = () in + Vif.Device.v ~name:"rsa_denom" ~finally [] @@ fun () -> + let rsa_l = List.map make_rsa Config.coins in + rsa_l diff --git a/src/secmod_keys.ml b/src/secmod_keys.ml new file mode 100644 index 00000000..c452724b --- /dev/null +++ b/src/secmod_keys.ml @@ -0,0 +1,21 @@ +type t = { + pub: Mirage_crypto_ec.Ed25519.pub; + sign: string -> string; +} + +let make ~name = + let finally _key = () in + Vif.Device.v ~name ~finally [] @@ fun () -> + (* TODO + - look if it exists + - if not, create it (TOFU initialization scheme) + - write it *) + let priv, pub = Mirage_crypto_ec.Ed25519.generate () in + { pub; sign= Mirage_crypto_ec.Ed25519.sign ~key:priv } + +let signkey_device = make ~name:"signkey" + +(* the actual exchange's signing key + signed by the secmod signkey *) +let exchange_device = make ~name:"exchange" +let denom_device = make ~name:"denom" diff --git a/src/types.ml b/src/types.ml index 28a7a7d7..5d138e1e 100644 --- a/src/types.ml +++ b/src/types.ml @@ -1,3 +1,33 @@ +module Config_types = struct + module Currency = struct + type t = { + enabled: [ `YES | `NO ]; + code: string; + name: string; + fractional_input_digits: int; + fractional_normal_digits: int; + fractional_trailing_zero_digits: int; + alt_unit_names: (int * string) list; + } + end + + module Coin = struct + type t = { + value: Amount.t; + duration_withdraw: int; + duration_spend: int; + duration_legal: int; + fee_withdraw: Amount.t; + fee_deposit: Amount.t; + fee_refresh: Amount.t; + fee_refund: Amount.t; + cipher: [ (* `CS |*) `RSA ]; + rsa_keysize: int option (*only if `RSA *); + age_restricted: [ (*`YES|*) `NO ]; + } + end +end + (* https://docs.taler.net/core/api-common.html#tsref-type-ErrorDetail *) module ErrorDetail = struct (* TODO GANA error codes @@ -41,7 +71,7 @@ module EddsaPublicKey = struct let of_string s = let open Mirage_crypto_ec in - match Base_32.decode s with + match B32.decode s with | Error _ as err -> err | Ok octets -> ( match Ed25519.pub_of_octets octets with @@ -49,7 +79,7 @@ module EddsaPublicKey = struct | Ok pub -> Ok pub) let to_string pub = - pub |> Mirage_crypto_ec.Ed25519.pub_to_octets |> Base_32.encode + pub |> Mirage_crypto_ec.Ed25519.pub_to_octets |> B32.encode end module EddsaSignature = struct @@ -69,22 +99,26 @@ end module RsaPublicKey = struct (* RSA public key converted to Crockford Base32. *) - type pub = Mirage_crypto_pk.Rsa.pub + type t = Mirage_crypto_pk.Rsa.pub - let pub_of_string s = + let of_string s = (* TODO bin - no [Bin.of_string] ? - what to do with the int ref? *) - let off = ref 0 in - let v = Bin.decode Binary_formats.RsaPublicKey.bin s off in - let res = Mirage_crypto_pk.Rsa.pub ~n:v.n ~e:v.e in - match res with Error (`Msg e) -> Error e | Ok pub -> Ok pub + match B32.decode s with + | Error _ as err -> err + | Ok s -> ( + let off = ref 0 in + let v = Bin.decode Binary_formats.RsaPublicKey.bin s off in + let res = Mirage_crypto_pk.Rsa.pub ~n:v.n ~e:v.e in + match res with Error (`Msg e) -> Error e | Ok pub -> Ok pub) - let pub_to_string ({ n; e } : Mirage_crypto_pk.Rsa.pub) = + let to_string ({ n; e } : Mirage_crypto_pk.Rsa.pub) = let open Binary_formats.RsaPublicKey in let header = { n_len= Z.size n; e_len= Z.size e } in let v = { header; n; e } in let s = Bin.to_string bin v in + let s = B32.encode s in s end @@ -133,3 +167,34 @@ module FutureSignKey = struct signkey_secmod_sig: EddsaSignature.t; } end + +module FutureDenom = struct + type t = { + section_name: string; + value: Amount.t; + stamp_start: Timestamp.t; + stamp_expire_withdraw: Timestamp.t; + stamp_expire_deposit: Timestamp.t; + stamp_expire_legal: Timestamp.t; + denom_pub: DenominationKey.t; + fee_withdraw: Amount.t; + fee_deposit: Amount.t; + fee_refresh: Amount.t; + fee_refund: Amount.t; + (* Signature by the denomination security module + over TALER_DenominationKeyAnnouncementPS + for this denomination with purpose + TALER_SIGNATURE_SM_DENOMINATION_KEY. *) + denom_secmod_sig: EddsaSignature.t; + } +end + +module FutureKeysResponse = struct + type t = { + future_denoms: FutureDenom.t list; + future_signkeys: FutureSignKey.t list; + master_pub: EddsaPublicKey.t; + denom_secmod_public_key: EddsaPublicKey.t; + signkey_secmod_public_key: EddsaPublicKey.t; + } +end