wip secmod

This commit is contained in:
swrup 2025-10-16 08:23:40 +02:00
parent 592ebee9a3
commit b27ebea6ee
8 changed files with 153 additions and 109 deletions

View file

@ -7,6 +7,8 @@
- checksum is not allowed *) - checksum is not allowed *)
(* 'I' 'L' 'O' 'U' excluded *) (* 'I' 'L' 'O' 'U' excluded *)
type t = string
let alphabet = Base32.make_alphabet "0123456789ABCDEFGHJKMNPQRSTVWXYZ" let alphabet = Base32.make_alphabet "0123456789ABCDEFGHJKMNPQRSTVWXYZ"
let encode s = Base32.encode_string ~alphabet s let encode s = Base32.encode_string ~alphabet s

View file

@ -22,26 +22,17 @@ module Exchange = struct
let enable_kyc = `NO let enable_kyc = `NO
end 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 = let currency_eur =
{ Types.Config_types.Currency.
enabled= `NO; {
code= "EUR"; enabled= `NO;
name= "euro"; code= "EUR";
fractional_input_digits= 2; name= "euro";
fractional_normal_digits= 2; fractional_input_digits= 2;
fractional_trailing_zero_digits= 2; fractional_normal_digits= 2;
alt_unit_names= [ (0, "E"); (3, "kE") ]; fractional_trailing_zero_digits= 2;
} alt_unit_names= [ (0, "E"); (3, "kE") ];
}
module Secmod_rsa = struct module Secmod_rsa = struct
let lookahead_sign = 9999999 let lookahead_sign = 9999999
@ -57,31 +48,21 @@ module Secmod_eddsa = struct
let key_dir = Fpath.(v "eddsa") let key_dir = Fpath.(v "eddsa")
end end
type coin = { let coin_kudo_1 =
value: Amount.t; Types.Config_types.Coin.
duration_withdraw: int; {
duration_spend: int; value= amount "EUR:0.01";
duration_legal: int; duration_withdraw= 999999;
fee_withdraw: Amount.t; duration_spend= 999999;
fee_deposit: Amount.t; duration_legal= 999999;
fee_refresh: Amount.t; fee_withdraw= amount "EUR:0.00";
fee_refund: Amount.t; fee_deposit= amount "EUR:0.00";
cipher: [ (* `CS |*) `RSA ]; fee_refresh= amount "EUR:0.00";
rsa_keysize: int option (*only if `RSA *); fee_refund= amount "EUR:0.00";
age_restricted: [ (*`YES|*) `NO ]; cipher= `RSA;
} rsa_keysize= Some 2048;
age_restricted= `NO;
}
let coin_kudo = let coin_kudo_2 = { coin_kudo_1 with value= amount "EUR:0.02" }
{ let coins = [ coin_kudo_1; coin_kudo_2 ]
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;
}

View file

@ -7,10 +7,10 @@
(library (library
(name mte) (name mte)
(wrapped false) (wrapped false)
(modules :standard \ mte base_32 amount) (modules :standard \ mte b32 amount)
(libraries (libraries
amount amount
base_32 b32
; ;
include include
; ;
@ -25,8 +25,8 @@
cohttp)) cohttp))
(library ; crockford base32 (library ; crockford base32
(name base_32) (name b32)
(modules base_32) (modules b32)
(libraries base32)) (libraries base32))
(library (library

View file

@ -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 exchanges 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)

View file

@ -125,8 +125,8 @@ let () =
let devices = let devices =
Vif.Devices. Vif.Devices.
[ [
Management.eddsa_online_key_device; Secmod_keys.signkey_device; Secmod_keys.denom_device;
Management.rsa_denomination_key_device; Secmod_denom.denom_device;
] ]
in in
let middlewares = Vif.Middlewares.[] in let middlewares = Vif.Middlewares.[] in

23
src/secmod_denom.ml Normal file
View file

@ -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

21
src/secmod_keys.ml Normal file
View file

@ -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"

View file

@ -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 *) (* https://docs.taler.net/core/api-common.html#tsref-type-ErrorDetail *)
module ErrorDetail = struct module ErrorDetail = struct
(* TODO GANA error codes (* TODO GANA error codes
@ -41,7 +71,7 @@ module EddsaPublicKey = struct
let of_string s = let of_string s =
let open Mirage_crypto_ec in let open Mirage_crypto_ec in
match Base_32.decode s with match B32.decode s with
| Error _ as err -> err | Error _ as err -> err
| Ok octets -> ( | Ok octets -> (
match Ed25519.pub_of_octets octets with match Ed25519.pub_of_octets octets with
@ -49,7 +79,7 @@ module EddsaPublicKey = struct
| Ok pub -> Ok pub) | Ok pub -> Ok pub)
let to_string 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 end
module EddsaSignature = struct module EddsaSignature = struct
@ -69,22 +99,26 @@ end
module RsaPublicKey = struct module RsaPublicKey = struct
(* RSA public key converted to Crockford Base32. *) (* 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 (* TODO bin
- no [Bin.of_string] ? - no [Bin.of_string] ?
- what to do with the int ref? *) - what to do with the int ref? *)
let off = ref 0 in match B32.decode s with
let v = Bin.decode Binary_formats.RsaPublicKey.bin s off in | Error _ as err -> err
let res = Mirage_crypto_pk.Rsa.pub ~n:v.n ~e:v.e in | Ok s -> (
match res with Error (`Msg e) -> Error e | Ok pub -> Ok pub 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 open Binary_formats.RsaPublicKey in
let header = { n_len= Z.size n; e_len= Z.size e } in let header = { n_len= Z.size n; e_len= Z.size e } in
let v = { header; n; e } in let v = { header; n; e } in
let s = Bin.to_string bin v in let s = Bin.to_string bin v in
let s = B32.encode s in
s s
end end
@ -133,3 +167,34 @@ module FutureSignKey = struct
signkey_secmod_sig: EddsaSignature.t; signkey_secmod_sig: EddsaSignature.t;
} }
end 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