mirror of
https://github.com/valitydev/kds.git
synced 2024-11-06 00:05:18 +00:00
CDS-79: Adds keyring meta (#2)
* CDS-79: Add keyring meta * CDS-79: Fix tests and specs * CDS-79: fixes to tests * CDS-79: encode binary in base64 in order to store in json * CDS-79: implement cds_proto Meta methods * CDS-79: Ensure that meta isn't overwritten by FSMs * CDS-79: Add backward compatibility storage tests * CDS-79: Fix dialyzer * CDS-79: Update keyring_path usage in test * CDS-79: Add meta tests * CDS-79: Add rotation meta collision test * CDS-79: Fix exception for update_meta during not_initialized * CDS-79: Move kds_keyring_storage_file specific function to module * CDS-79: spec fix * CDS-79: replace dumb copy with symlink * CDS-89: Add GetKeyring method with SSL (#3) * CDS-89: Add ability to get keyring from storage * CDS-89: replace dumb copy with symlink * CDS-89: Add ssl support for keyring storage api * Update apps/kds/test/kds_keyring_storage_api_tests_SUITE.erl Co-Authored-By: Sergei Shuvatov <Yozhig@users.noreply.github.com> * Update apps/kds/test/kds_keyring_storage_api_tests_SUITE.erl Co-Authored-By: Sergei Shuvatov <Yozhig@users.noreply.github.com> * Update apps/kds/test/kds_keyring_client.erl Co-Authored-By: Sergei Shuvatov <Yozhig@users.noreply.github.com> * Update apps/kds/test/kds_keyring_client.erl Co-Authored-By: Sergei Shuvatov <Yozhig@users.noreply.github.com> * CDS-89: Review fix * CDS-89: sys.config update * CDS-79: Review fix * CDS-79: Review fix * CDS-79: Review fix * CDS-79: Refactor meta validation * CDS-79: Add error if UpdateKeyringMeta doesn't make changes * CDS-79: Fix initializer returning actual keyring instead of diff. * CDS-79: spec fix * CDS-79: fix rotator and kds_keyring specs * CDS-79: remove ability to make meta updates if not_initialized * Update apps/kds/src/kds_keyring_management_thrift_handler.erl Co-Authored-By: Sergei Shuvatov <Yozhig@users.noreply.github.com> * CDS-79: remove useless slash in string * CDS-79: fix storage file decoding * CDS-79: bump handler version and move same meta check to manager * CDS-79: add format version to keyring storage for decoding * CDS-79: Add version to keyring meta * CDS-79: Remove diffs for keyring * CDS-79: type fix * CDS-79: Move keyring_meta types to it's module * CDS-79: replace string generation with converting Reason to binary * CDS-79: Update encrypted keyring format and rename current_key to max_key_id * CDS-79: Refactor * CDS-79: Update doc * CDS-79: Remove validation failed and bump cds_proto version * CDS-79: Add ability to change current_key_id in meta * CDS-79: Fix missing exceptions in handler
This commit is contained in:
parent
5290f88d44
commit
6114ce6a0e
@ -35,21 +35,36 @@ stop() ->
|
||||
init([]) ->
|
||||
{ok, IP} = inet:parse_address(application:get_env(kds, ip, "::")),
|
||||
HealthCheckers = genlib_app:env(?MODULE, health_checkers, []),
|
||||
Service = woody_server:child_spec(
|
||||
kds_thrift_service_sup,
|
||||
KeyringManagementService = woody_server:child_spec(
|
||||
kds_thrift_management_service_sup,
|
||||
#{
|
||||
handlers => [
|
||||
kds_thrift_services:http_handler(keyring_v2)
|
||||
kds_thrift_services:http_handler(keyring_management)
|
||||
],
|
||||
event_handler => scoper_woody_event_handler,
|
||||
ip => IP,
|
||||
port => genlib_app:env(?MODULE, port, 8022),
|
||||
transport_opts => genlib_app:env(?MODULE, transport_opts, #{}),
|
||||
port => genlib_app:env(?MODULE, management_port, 8022),
|
||||
transport_opts => genlib_app:env(?MODULE, management_transport_opts, #{}),
|
||||
protocol_opts => genlib_app:env(?MODULE, protocol_opts, #{}),
|
||||
shutdown_timeout => genlib_app:env(?MODULE, shutdown_timeout, 0),
|
||||
additional_routes => [erl_health_handle:get_route(HealthCheckers)]
|
||||
}
|
||||
),
|
||||
KeyringStorageService = woody_server:child_spec(
|
||||
kds_thrift_storage_service_sup,
|
||||
#{
|
||||
handlers => [
|
||||
kds_thrift_services:http_handler(keyring_storage)
|
||||
],
|
||||
event_handler => scoper_woody_event_handler,
|
||||
ip => IP,
|
||||
port => genlib_app:env(?MODULE, storage_port, 8023),
|
||||
transport_opts => genlib_app:env(?MODULE, storage_transport_opts, #{}),
|
||||
protocol_opts => genlib_app:env(?MODULE, protocol_opts, #{}),
|
||||
shutdown_timeout => genlib_app:env(?MODULE, shutdown_timeout, 0),
|
||||
additional_routes => []
|
||||
}
|
||||
),
|
||||
KeyringSupervisor = #{
|
||||
id => kds_keyring_sup,
|
||||
start => {kds_keyring_sup, start_link, []},
|
||||
@ -60,7 +75,8 @@ init([]) ->
|
||||
Procs = [
|
||||
KeyringStorage,
|
||||
KeyringSupervisor,
|
||||
Service
|
||||
KeyringManagementService,
|
||||
KeyringStorageService
|
||||
],
|
||||
{ok, {{one_for_one, 1, 5}, Procs}}.
|
||||
|
||||
|
@ -21,7 +21,7 @@ call(Key, Method, Args) ->
|
||||
throw(Error)
|
||||
catch Class:Reason:Stacktrace ->
|
||||
_ = logger:error(
|
||||
"~p (~p) ~p failed~nClass~s~nReason~s",
|
||||
"~p (~p) ~p failed~nClass: ~s~nReason: ~s",
|
||||
[Key, Module, Method, Class, Reason],
|
||||
#{stacktrace => genlib_format:format_stacktrace(Stacktrace)}),
|
||||
handle_error(Class, Reason)
|
||||
|
@ -17,38 +17,66 @@
|
||||
-export_type([key/0]).
|
||||
-export_type([key_id/0]).
|
||||
-export_type([keyring/0]).
|
||||
-export_type([keyring_data/0]).
|
||||
-export_type([encrypted_keyring/0]).
|
||||
|
||||
-type masterkey() :: kds_keysharing:masterkey().
|
||||
-type key() :: binary().
|
||||
-type key_id() :: byte().
|
||||
-type encrypted_keyring() :: binary().
|
||||
-type encrypted_keyring() :: #{
|
||||
data := binary(),
|
||||
meta := keyring_meta() | undefined
|
||||
}.
|
||||
-type keyring_meta() :: kds_keyring_meta:keyring_meta().
|
||||
|
||||
-type keyring() :: #{
|
||||
current_key := key_id(),
|
||||
data := keyring_data(),
|
||||
meta := keyring_meta()
|
||||
}.
|
||||
|
||||
-type keyring_data() :: #{
|
||||
keys := #{key_id() => key()}
|
||||
}.
|
||||
|
||||
-define(KEY_BYTESIZE, 32).
|
||||
-define(FORMAT_VERSION, 1).
|
||||
|
||||
%%
|
||||
|
||||
-spec new() -> keyring().
|
||||
new() ->
|
||||
#{current_key => 0, keys => #{0 => kds_crypto:key()}}.
|
||||
#{
|
||||
data => #{
|
||||
keys => #{0 => kds_crypto:key()}
|
||||
},
|
||||
meta => #{
|
||||
current_key_id => 0,
|
||||
version => 1,
|
||||
keys => #{
|
||||
0 => #{
|
||||
retired => false
|
||||
}
|
||||
}
|
||||
}
|
||||
}.
|
||||
|
||||
-spec rotate(keyring()) -> keyring().
|
||||
rotate(#{current_key := CurrentKeyId, keys := Keys}) ->
|
||||
<<NewCurrentKeyId>> = <<(CurrentKeyId + 1)>>,
|
||||
case maps:is_key(NewCurrentKeyId, Keys) of
|
||||
false ->
|
||||
#{current_key => NewCurrentKeyId, keys => Keys#{NewCurrentKeyId => kds_crypto:key()}};
|
||||
true ->
|
||||
throw(keyring_full)
|
||||
end.
|
||||
rotate(#{data := #{keys := Keys}, meta := #{current_key_id := CurrentKeyId, version := Version, keys := KeysMeta}}) ->
|
||||
MaxKeyId = lists:max(maps:keys(Keys)),
|
||||
NewMaxKeyId = MaxKeyId + 1,
|
||||
#{
|
||||
data => #{
|
||||
keys => Keys#{NewMaxKeyId => kds_crypto:key()}
|
||||
},
|
||||
meta => #{
|
||||
current_key_id => CurrentKeyId,
|
||||
version => Version + 1,
|
||||
keys => KeysMeta#{NewMaxKeyId => #{retired => false}}
|
||||
}
|
||||
}.
|
||||
|
||||
-spec get_key(key_id(), keyring()) -> {ok, {key_id(), key()}} | {error, not_found}.
|
||||
get_key(KeyId, #{keys := Keys}) ->
|
||||
get_key(KeyId, #{data := #{keys := Keys}}) ->
|
||||
case maps:find(KeyId, Keys) of
|
||||
{ok, Key} ->
|
||||
{ok, {KeyId, Key}};
|
||||
@ -57,38 +85,58 @@ get_key(KeyId, #{keys := Keys}) ->
|
||||
end.
|
||||
|
||||
-spec get_keys(keyring()) -> [{key_id(), key()}].
|
||||
get_keys(#{keys := Keys}) ->
|
||||
get_keys(#{data := #{keys := Keys}}) ->
|
||||
maps:to_list(Keys).
|
||||
|
||||
-spec get_current_key(keyring()) -> {key_id(), key()}.
|
||||
get_current_key(#{current_key := CurrentKeyId, keys := Keys}) ->
|
||||
get_current_key(#{data := #{keys := Keys}, meta := #{current_key_id := CurrentKeyId}}) ->
|
||||
CurrentKey = maps:get(CurrentKeyId, Keys),
|
||||
{CurrentKeyId, CurrentKey}.
|
||||
|
||||
%%
|
||||
|
||||
-spec encrypt(key(), keyring()) -> encrypted_keyring().
|
||||
encrypt(MasterKey, Keyring) ->
|
||||
kds_crypto:encrypt(MasterKey, marshall(Keyring)).
|
||||
encrypt(MasterKey, #{data := KeyringData, meta := KeyringMeta}) ->
|
||||
#{
|
||||
data => base64:encode(kds_crypto:encrypt(MasterKey, marshall(KeyringData))),
|
||||
meta => KeyringMeta
|
||||
}.
|
||||
|
||||
-spec decrypt(key(), encrypted_keyring()) -> {ok, keyring()} | {error, decryption_failed}.
|
||||
decrypt(MasterKey, EncryptedKeyring) ->
|
||||
try {ok, unmarshall(kds_crypto:decrypt(MasterKey, EncryptedKeyring))} catch
|
||||
decrypt(MasterKey, #{data := EncryptedKeyringData, meta := KeyringMeta}) ->
|
||||
try unmarshall(kds_crypto:decrypt(MasterKey, base64:decode(EncryptedKeyringData))) of
|
||||
KeyringData ->
|
||||
case KeyringMeta of
|
||||
undefined ->
|
||||
{ok, #{
|
||||
data => KeyringData,
|
||||
meta => kds_keyring_meta:get_default_keyring_meta(KeyringData)
|
||||
}};
|
||||
_ ->
|
||||
{ok, #{data => KeyringData, meta => KeyringMeta}}
|
||||
end
|
||||
catch
|
||||
decryption_failed ->
|
||||
{error, decryption_failed}
|
||||
end.
|
||||
|
||||
-spec marshall(keyring()) -> binary().
|
||||
marshall(#{current_key := CurrentKey, keys := Keys}) ->
|
||||
<<CurrentKey, (maps:fold(fun marshall_keys/3, <<>>, Keys))/binary>>.
|
||||
-spec marshall(keyring_data()) -> binary().
|
||||
marshall(#{keys := Keys}) ->
|
||||
Keyring = erlang:term_to_binary(#{
|
||||
keys => Keys
|
||||
}),
|
||||
<<?FORMAT_VERSION:8/integer-unit:4, Keyring/binary>>.
|
||||
|
||||
-spec unmarshall(binary()) -> keyring().
|
||||
unmarshall(<<CurrentKey, Keys/binary>>) ->
|
||||
#{current_key => CurrentKey, keys => unmarshall_keys(Keys, #{})}.
|
||||
|
||||
-spec marshall_keys(key_id(), key(), binary()) -> binary().
|
||||
marshall_keys(KeyId, Key, Acc) ->
|
||||
<<Acc/binary, KeyId, Key:?KEY_BYTESIZE/binary>>.
|
||||
-spec unmarshall(binary()) -> keyring_data().
|
||||
unmarshall(<<MaxKeyId, Keys/binary>> = MarshalledKeyring) ->
|
||||
KeysSize = erlang:byte_size(Keys),
|
||||
case (KeysSize div 33 =:= MaxKeyId) and (KeysSize rem 33 =:= 0) of
|
||||
true ->
|
||||
#{keys => unmarshall_keys(Keys, #{})};
|
||||
false ->
|
||||
<<1:8/integer-unit:4, Keyring/binary>> = MarshalledKeyring,
|
||||
erlang:binary_to_term(Keyring, [safe])
|
||||
end.
|
||||
|
||||
-spec unmarshall_keys(binary(), map()) -> map().
|
||||
unmarshall_keys(<<>>, Acc) ->
|
||||
|
@ -69,7 +69,7 @@ initialize(Threshold) ->
|
||||
call({initialize, Threshold}).
|
||||
|
||||
-spec validate(shareholder_id(), masterkey_share()) ->
|
||||
{ok, {more, integer()}} |
|
||||
{ok, {more, pos_integer()}} |
|
||||
{ok, {done, {encrypted_keyring(), decrypted_keyring()}}} |
|
||||
{error, validate_errors()} | invalid_activity().
|
||||
|
||||
@ -158,7 +158,7 @@ handle_event({call, From}, get_status, State, #data{timer = TimerRef, shares = V
|
||||
},
|
||||
{keep_state_and_data, {reply, From, Status}};
|
||||
handle_event({call, From}, cancel, _State, #data{timer = TimerRef}) ->
|
||||
_ = erlang:cancel_timer(TimerRef),
|
||||
ok = cancel_timer(TimerRef),
|
||||
{next_state, uninitialized, #data{}, {reply, From, ok}};
|
||||
handle_event(info, {timeout, _TimerRef, lifetime_expired}, _State, _Data) ->
|
||||
{next_state, uninitialized, #data{}, []};
|
||||
@ -204,3 +204,9 @@ validate(Threshold, Shares, EncryptedKeyring) ->
|
||||
{error, Error} ->
|
||||
{error, {operation_aborted, Error}}
|
||||
end.
|
||||
|
||||
cancel_timer(undefined) ->
|
||||
ok;
|
||||
cancel_timer(TimerRef) ->
|
||||
_ = erlang:cancel_timer(TimerRef),
|
||||
ok.
|
@ -1,4 +1,4 @@
|
||||
-module(kds_keyring_v2_thrift_handler).
|
||||
-module(kds_keyring_management_thrift_handler).
|
||||
-behaviour(woody_server_thrift_handler).
|
||||
|
||||
-include_lib("cds_proto/include/cds_proto_keyring_thrift.hrl").
|
||||
@ -17,7 +17,7 @@
|
||||
|
||||
handle_function(OperationID, Args, Context, Opts) ->
|
||||
scoper:scope(
|
||||
keyring_v2,
|
||||
keyring_management,
|
||||
fun() -> handle_function_(OperationID, Args, Context, Opts) end
|
||||
).
|
||||
|
||||
@ -81,6 +81,8 @@ handle_function_('ConfirmUnlock', [ShareholderId, Share], _Context, _Opts) ->
|
||||
raise(#'VerificationFailed'{});
|
||||
{invalid_status, Status} ->
|
||||
raise(#'InvalidStatus'{status = Status});
|
||||
{invalid_activity, Activity} ->
|
||||
raise(#'InvalidActivity'{activity = Activity});
|
||||
{operation_aborted, Reason} ->
|
||||
raise(#'OperationAborted'{reason = atom_to_binary(Reason, utf8)})
|
||||
end;
|
||||
@ -108,6 +110,8 @@ handle_function_('ConfirmRotate', [ShareholderId, Share], _Context, _Opts) ->
|
||||
raise(#'VerificationFailed'{});
|
||||
{invalid_status, Status} ->
|
||||
raise(#'InvalidStatus'{status = Status});
|
||||
{invalid_activity, Activity} ->
|
||||
raise(#'InvalidActivity'{activity = Activity});
|
||||
{operation_aborted, Reason} ->
|
||||
raise(#'OperationAborted'{reason = atom_to_binary(Reason, utf8)})
|
||||
end;
|
||||
@ -175,7 +179,25 @@ handle_function_('GetState', [], _Context, _Opts) ->
|
||||
case kds_keyring_manager:get_status() of
|
||||
Status ->
|
||||
{ok, encode_state(Status)}
|
||||
end.
|
||||
end;
|
||||
|
||||
handle_function_('UpdateKeyringMeta', [KeyringMeta], _Context, _Opts) ->
|
||||
try
|
||||
DecodedKeyringMeta = kds_keyring_meta:decode_keyring_meta_diff(KeyringMeta),
|
||||
kds_keyring_manager:update_meta(DecodedKeyringMeta)
|
||||
of
|
||||
ok ->
|
||||
{ok, ok}
|
||||
catch
|
||||
{invalid_status, Status} ->
|
||||
raise(#'InvalidStatus'{status = Status});
|
||||
{validation_failed, Reason} ->
|
||||
raise(#'InvalidKeyringMeta'{reason = erlang:atom_to_binary(Reason, utf8)})
|
||||
end;
|
||||
handle_function_('GetKeyringMeta', [], _Context, _Opts) ->
|
||||
KeyringMeta = kds_keyring_manager:get_meta(),
|
||||
EncodedKeyringMeta = kds_keyring_meta:encode_keyring_meta(KeyringMeta),
|
||||
{ok, EncodedKeyringMeta}.
|
||||
|
||||
-spec encode_encrypted_shares([kds_keysharing:encrypted_master_key_share()]) ->
|
||||
[encrypted_masterkey_share()].
|
@ -22,6 +22,8 @@
|
||||
-export([validate_rekey/2]).
|
||||
-export([cancel_rekey/0]).
|
||||
-export([get_status/0]).
|
||||
-export([update_meta/1]).
|
||||
-export([get_meta/0]).
|
||||
|
||||
%% gen_statem.
|
||||
-export([init/1]).
|
||||
@ -35,7 +37,10 @@
|
||||
-define(STATEM, ?MODULE).
|
||||
|
||||
-record(data, {
|
||||
keyring :: kds_keyring:keyring() | undefined
|
||||
keyring :: #{
|
||||
data := undefined | kds_keyring:keyring_data(),
|
||||
meta := undefined | kds_keyring_meta:keyring_meta()
|
||||
}
|
||||
}).
|
||||
|
||||
-type data() :: #data{}.
|
||||
@ -68,7 +73,7 @@ start_unlock() ->
|
||||
call(start_unlock).
|
||||
|
||||
-spec confirm_unlock(kds_shareholder:shareholder_id(), kds_keysharing:masterkey_share()) ->
|
||||
{more, non_neg_integer()} | ok.
|
||||
{more, pos_integer()} | ok.
|
||||
confirm_unlock(ShareholderId, Share) ->
|
||||
call({confirm_unlock, ShareholderId, Share}).
|
||||
|
||||
@ -85,7 +90,7 @@ start_rotate() ->
|
||||
call(start_rotate).
|
||||
|
||||
-spec confirm_rotate(kds_shareholder:shareholder_id(), kds_keysharing:masterkey_share()) ->
|
||||
{more, non_neg_integer()} | ok.
|
||||
{more, pos_integer()} | ok.
|
||||
confirm_rotate(ShareholderId, Share) ->
|
||||
call({confirm_rotate, ShareholderId, Share}).
|
||||
|
||||
@ -98,7 +103,7 @@ initialize(Threshold) ->
|
||||
call({initialize, Threshold}).
|
||||
|
||||
-spec validate_init(kds_shareholder:shareholder_id(), kds_keysharing:masterkey_share()) ->
|
||||
{more, non_neg_integer()} | ok.
|
||||
{more, pos_integer()} | ok.
|
||||
validate_init(ShareholderId, Share) ->
|
||||
call({validate_init, ShareholderId, Share}).
|
||||
|
||||
@ -111,7 +116,7 @@ start_rekey(Threshold) ->
|
||||
call({start_rekey, Threshold}).
|
||||
|
||||
-spec confirm_rekey(kds_shareholder:shareholder_id(), kds_keysharing:masterkey_share()) ->
|
||||
{more, non_neg_integer()} | ok.
|
||||
{more, pos_integer()} | ok.
|
||||
confirm_rekey(ShareholderId, Share) ->
|
||||
call({confirm_rekey, ShareholderId, Share}).
|
||||
|
||||
@ -120,7 +125,7 @@ start_validate_rekey() ->
|
||||
call(start_validate_rekey).
|
||||
|
||||
-spec validate_rekey(kds_shareholder:shareholder_id(), kds_keysharing:masterkey_share()) ->
|
||||
{more, non_neg_integer()} | ok.
|
||||
{more, pos_integer()} | ok.
|
||||
validate_rekey(ShareholderId, Share) ->
|
||||
call({validate_rekey, ShareholderId, Share}).
|
||||
|
||||
@ -132,6 +137,14 @@ cancel_rekey() ->
|
||||
get_status() ->
|
||||
call(get_status).
|
||||
|
||||
-spec update_meta(kds_keyring_meta:keyring_meta_diff()) -> ok.
|
||||
update_meta(KeyringMeta) ->
|
||||
call({update_meta, KeyringMeta}).
|
||||
|
||||
-spec get_meta() -> kds_keyring_meta:keyring_meta().
|
||||
get_meta() ->
|
||||
call(get_meta).
|
||||
|
||||
call(Event) ->
|
||||
case gen_statem:call(?STATEM, Event) of
|
||||
ok ->
|
||||
@ -147,11 +160,11 @@ call(Event) ->
|
||||
-spec init(_) -> {ok, locked | not_initialized, data()}.
|
||||
init([]) ->
|
||||
try kds_keyring_storage:read() of
|
||||
_Keyring ->
|
||||
{ok, locked, #data{keyring = undefined}}
|
||||
#{meta := KeyringMeta} ->
|
||||
{ok, locked, #data{keyring = #{data => undefined, meta => KeyringMeta}}}
|
||||
catch
|
||||
not_found ->
|
||||
{ok, not_initialized, #data{}}
|
||||
{ok, not_initialized, #data{keyring = #{data => undefined, meta => undefined}}}
|
||||
end.
|
||||
|
||||
-spec handle_event(gen_statem:event_type(), term(), state(), data()) ->
|
||||
@ -180,15 +193,15 @@ handle_event({call, From}, cancel_init, not_initialized, _StateData) ->
|
||||
%% locked events
|
||||
|
||||
handle_event({call, From}, start_unlock, locked, _StateData) ->
|
||||
LockedKeyring = kds_keyring_storage:read(),
|
||||
Result = kds_keyring_unlocker:initialize(LockedKeyring),
|
||||
Result = kds_keyring_unlocker:initialize(),
|
||||
{keep_state_and_data, {reply, From, Result}};
|
||||
handle_event({call, From}, {confirm_unlock, ShareholderId, Share}, locked, StateData) ->
|
||||
case kds_keyring_unlocker:confirm(ShareholderId, Share) of
|
||||
LockedKeyring = kds_keyring_storage:read(),
|
||||
case kds_keyring_unlocker:confirm(ShareholderId, Share, LockedKeyring) of
|
||||
{ok, {more, _More}} = Result ->
|
||||
{keep_state_and_data, {reply, From, Result}};
|
||||
{ok, {done, UnlockedKeyring}} ->
|
||||
NewStateData = StateData#data{keyring = UnlockedKeyring},
|
||||
{ok, {done, Keyring}} ->
|
||||
NewStateData = StateData#data{keyring = Keyring},
|
||||
{next_state, unlocked, NewStateData, {reply, From, ok}};
|
||||
{error, Error} ->
|
||||
{keep_state_and_data, {reply, From, {error, Error}}}
|
||||
@ -199,20 +212,21 @@ handle_event({call, From}, cancel_unlock, locked, _StateData) ->
|
||||
|
||||
%% unlocked events
|
||||
|
||||
handle_event({call, From}, lock, unlocked, StateData) ->
|
||||
{next_state, locked, StateData#data{keyring = undefined}, {reply, From, ok}};
|
||||
handle_event({call, From}, lock, unlocked, #data{keyring = Keyring} = StateData) ->
|
||||
{next_state, locked, StateData#data{keyring = Keyring#{data => undefined}}, {reply, From, ok}};
|
||||
handle_event({call, From}, get_keyring, unlocked, #data{keyring = Keyring}) ->
|
||||
{keep_state_and_data, {reply, From, {ok, Keyring}}};
|
||||
handle_event({call, From}, start_rotate, unlocked, #data{keyring = OldKeyring}) ->
|
||||
EncryptedKeyring = kds_keyring_storage:read(),
|
||||
Result = kds_keyring_rotator:initialize(OldKeyring, EncryptedKeyring),
|
||||
handle_event({call, From}, start_rotate, unlocked, _StateData) ->
|
||||
Result = kds_keyring_rotator:initialize(),
|
||||
{keep_state_and_data, {reply, From, Result}};
|
||||
handle_event({call, From}, {confirm_rotate, ShareholderId, Share}, unlocked, StateData) ->
|
||||
case kds_keyring_rotator:confirm(ShareholderId, Share) of
|
||||
handle_event({call, From}, {confirm_rotate, ShareholderId, Share}, unlocked,
|
||||
#data{keyring = OldKeyring} = StateData) ->
|
||||
EncryptedKeyring = kds_keyring_storage:read(),
|
||||
case kds_keyring_rotator:confirm(ShareholderId, Share, EncryptedKeyring, OldKeyring) of
|
||||
{ok, {more, _More}} = Result ->
|
||||
{keep_state_and_data, {reply, From, Result}};
|
||||
{ok, {done, {EncryptedNewKeyring, NewKeyring}}} ->
|
||||
ok = kds_keyring_storage:update(EncryptedNewKeyring),
|
||||
{ok, {done, {NewEncryptedKeyring, NewKeyring}}} ->
|
||||
ok = kds_keyring_storage:update(NewEncryptedKeyring),
|
||||
NewStateData = StateData#data{keyring = NewKeyring},
|
||||
{keep_state, NewStateData, {reply, From, ok}};
|
||||
{error, Error} ->
|
||||
@ -222,21 +236,21 @@ handle_event({call, From}, cancel_rotate, unlocked, _StateData) ->
|
||||
ok = kds_keyring_rotator:cancel(),
|
||||
{keep_state_and_data, {reply, From, ok}};
|
||||
handle_event({call, From}, {start_rekey, Threshold}, unlocked, _StateData) ->
|
||||
EncryptedKeyring = kds_keyring_storage:read(),
|
||||
Result = kds_keyring_rekeyer:initialize(Threshold, EncryptedKeyring),
|
||||
Result = kds_keyring_rekeyer:initialize(Threshold),
|
||||
{keep_state_and_data, {reply, From, Result}};
|
||||
handle_event({call, From}, {confirm_rekey, ShareholderId, Share}, unlocked, _StateData) ->
|
||||
Result = kds_keyring_rekeyer:confirm(ShareholderId, Share),
|
||||
EncryptedKeyring = kds_keyring_storage:read(),
|
||||
Result = kds_keyring_rekeyer:confirm(ShareholderId, Share, EncryptedKeyring),
|
||||
{keep_state_and_data, {reply, From, Result}};
|
||||
handle_event({call, From}, start_validate_rekey, unlocked, _StateData) ->
|
||||
Result = kds_keyring_rekeyer:start_validation(),
|
||||
handle_event({call, From}, start_validate_rekey, unlocked, #data{keyring = Keyring}) ->
|
||||
Result = kds_keyring_rekeyer:start_validation(Keyring),
|
||||
{keep_state_and_data, {reply, From, Result}};
|
||||
handle_event({call, From}, {validate_rekey, ShareholderId, Share}, unlocked, _StateData) ->
|
||||
case kds_keyring_rekeyer:validate(ShareholderId, Share) of
|
||||
handle_event({call, From}, {validate_rekey, ShareholderId, Share}, unlocked, #data{keyring = Keyring}) ->
|
||||
case kds_keyring_rekeyer:validate(ShareholderId, Share, Keyring) of
|
||||
{ok, {more, _More}} = Result ->
|
||||
{keep_state_and_data, {reply, From, Result}};
|
||||
{ok, {done, EncryptedNewKeyring}} ->
|
||||
ok = kds_keyring_storage:update(EncryptedNewKeyring),
|
||||
{ok, {done, EncryptedKeyring}} ->
|
||||
ok = kds_keyring_storage:update(EncryptedKeyring),
|
||||
{keep_state_and_data, {reply, From, ok}};
|
||||
{error, Error} ->
|
||||
{keep_state_and_data, {reply, From, {error, Error}}}
|
||||
@ -245,12 +259,29 @@ handle_event({call, From}, cancel_rekey, unlocked, _StateData) ->
|
||||
ok = kds_keyring_rekeyer:cancel(),
|
||||
{keep_state_and_data, {reply, From, ok}};
|
||||
|
||||
%% common events
|
||||
|
||||
handle_event({call, From}, get_status, State, _Data) ->
|
||||
{keep_state_and_data, {reply, From, {ok, generate_status(State)}}};
|
||||
handle_event({call, From}, {update_meta, _UpdateKeyringMeta}, not_initialized, _StateData) ->
|
||||
{keep_state_and_data, {reply, From, {error, {invalid_status, not_initialized}}}};
|
||||
handle_event({call, From}, {update_meta, UpdateKeyringMeta}, _State,
|
||||
#data{keyring = #{meta := KeyringMeta} = Keyring} = Data) ->
|
||||
case kds_keyring_meta:update_meta(KeyringMeta, UpdateKeyringMeta) of
|
||||
KeyringMeta ->
|
||||
{keep_state_and_data, {reply, From, {ok, ok}}};
|
||||
NewKeyringMeta ->
|
||||
EncryptedKeyring = kds_keyring_storage:read(),
|
||||
NewEncryptedKeyring = EncryptedKeyring#{meta => NewKeyringMeta},
|
||||
ok = kds_keyring_storage:update(NewEncryptedKeyring),
|
||||
NewKeyring = Keyring#{meta => NewKeyringMeta},
|
||||
{keep_state, Data#data{keyring = NewKeyring}, {reply, From, {ok, ok}}}
|
||||
end;
|
||||
handle_event({call, From}, get_meta, _State, #data{keyring = #{meta := KeyringMeta}}) ->
|
||||
{keep_state_and_data, {reply, From, {ok, KeyringMeta}}};
|
||||
handle_event({call, From}, _Event, State, _StateData) ->
|
||||
{keep_state_and_data, {reply, From, {error, {invalid_status, State}}}}.
|
||||
|
||||
|
||||
-spec generate_status(atom()) -> status().
|
||||
generate_status(StateName) ->
|
||||
#{
|
||||
|
124
apps/kds/src/kds_keyring_meta.erl
Normal file
124
apps/kds/src/kds_keyring_meta.erl
Normal file
@ -0,0 +1,124 @@
|
||||
-module(kds_keyring_meta).
|
||||
|
||||
-include_lib("cds_proto/include/cds_proto_keyring_thrift.hrl").
|
||||
|
||||
%% API
|
||||
-export([get_default_keyring_meta/1]).
|
||||
-export([update_meta/2]).
|
||||
-export([decode_keyring_meta_diff/1]).
|
||||
-export([decode_keyring_meta/1]).
|
||||
-export([encode_keyring_meta_diff/1]).
|
||||
-export([encode_keyring_meta/1]).
|
||||
|
||||
-export_type([keyring_meta/0]).
|
||||
-export_type([keyring_meta_diff/0]).
|
||||
|
||||
-type keyring_meta() :: #{
|
||||
current_key_id := non_neg_integer(),
|
||||
version := pos_integer(),
|
||||
keys := #{
|
||||
key_id() => key_meta()
|
||||
}
|
||||
}.
|
||||
-type keyring_meta_diff() :: #{
|
||||
current_key_id => non_neg_integer() | undefined,
|
||||
keys => #{
|
||||
key_id() => key_meta()
|
||||
} | undefined
|
||||
}.
|
||||
-type key_meta() :: #{
|
||||
retired := boolean()
|
||||
}.
|
||||
-type key_id() :: kds_keyring:key_id().
|
||||
-type encoded_keyring_meta() :: #'KeyringMeta'{}.
|
||||
-type encoded_keyring_meta_diff() :: #'KeyringMetaDiff'{}.
|
||||
|
||||
-spec get_default_keyring_meta(kds_keyring:keyring_data()) -> keyring_meta().
|
||||
get_default_keyring_meta(KeyringData) ->
|
||||
Keys = maps:get(keys, KeyringData),
|
||||
CurrentKeyId = lists:max(maps:keys(Keys)),
|
||||
KeysMeta = maps:map(fun (_KeyId, _Key) -> #{retired => false} end, Keys),
|
||||
#{current_key_id => CurrentKeyId, version => 1, keys => KeysMeta}.
|
||||
|
||||
-spec update_meta(keyring_meta(), keyring_meta_diff()) -> keyring_meta().
|
||||
update_meta(#{current_key_id := OldCurrentKeyId, version := Version, keys := OldKeysMeta} = OldMeta, UpdateMeta) ->
|
||||
KeysMeta = maps:get(keys, UpdateMeta, undefined),
|
||||
UpdatedKeysMeta = update_keys_meta(OldKeysMeta, KeysMeta),
|
||||
CurrentKeyId = maps:get(current_key_id, UpdateMeta, undefined),
|
||||
UpdatedCurrentKeyId = update_current_key_id(OldCurrentKeyId, CurrentKeyId),
|
||||
case OldMeta#{current_key_id => UpdatedCurrentKeyId, keys => UpdatedKeysMeta} of
|
||||
OldMeta ->
|
||||
OldMeta;
|
||||
NewMeta ->
|
||||
NewMeta#{version => Version + 1}
|
||||
end.
|
||||
|
||||
update_keys_meta(OldKeysMeta, undefined) ->
|
||||
OldKeysMeta;
|
||||
update_keys_meta(OldKeysMeta, UpdateKeysMeta) ->
|
||||
maps:fold(
|
||||
fun(K, V, Acc) ->
|
||||
UpdateKeyMeta = maps:get(K, UpdateKeysMeta, #{}),
|
||||
Acc#{K => maps:merge(V, UpdateKeyMeta)}
|
||||
end,
|
||||
#{}, OldKeysMeta).
|
||||
|
||||
update_current_key_id(OldCurrentKeyId, undefined) ->
|
||||
OldCurrentKeyId;
|
||||
update_current_key_id(_OldCurrentKeyId, NewCurrentKeyId) ->
|
||||
NewCurrentKeyId.
|
||||
|
||||
-spec decode_keyring_meta_diff(encoded_keyring_meta_diff()) -> keyring_meta_diff().
|
||||
decode_keyring_meta_diff(#'KeyringMetaDiff'{
|
||||
current_key_id = CurrentKeyId,
|
||||
keys_meta = KeysMeta
|
||||
}) ->
|
||||
DecodedKeysMeta = decode_keys_meta(KeysMeta),
|
||||
#{current_key_id => CurrentKeyId, keys => DecodedKeysMeta}.
|
||||
|
||||
-spec decode_keyring_meta(encoded_keyring_meta()) -> keyring_meta().
|
||||
decode_keyring_meta(#'KeyringMeta'{
|
||||
current_key_id = CurrentKeyId,
|
||||
keys_meta = KeysMeta
|
||||
}) ->
|
||||
DecodedKeysMeta = decode_keys_meta(KeysMeta),
|
||||
#{current_key_id => CurrentKeyId, version => 1, keys => DecodedKeysMeta}.
|
||||
|
||||
decode_keys_meta(undefined) ->
|
||||
undefined;
|
||||
decode_keys_meta(KeysMeta) ->
|
||||
maps:fold(
|
||||
fun (K, #'KeyMeta'{retired = Retired}, Acc) ->
|
||||
Acc#{K => #{retired => Retired}}
|
||||
end,
|
||||
#{},
|
||||
KeysMeta).
|
||||
|
||||
-spec encode_keyring_meta_diff(keyring_meta_diff()) -> encoded_keyring_meta_diff().
|
||||
encode_keyring_meta_diff(KeyringMetaDiff) ->
|
||||
#'KeyringMetaDiff'{
|
||||
current_key_id = maps:get(current_key_id, KeyringMetaDiff, undefined),
|
||||
keys_meta = encode_keys_meta(maps:get(keys, KeyringMetaDiff, undefined))
|
||||
}.
|
||||
|
||||
-spec encode_keyring_meta(keyring_meta() | undefined) -> encoded_keyring_meta().
|
||||
encode_keyring_meta(undefined) ->
|
||||
#'KeyringMeta'{current_key_id = 0, keys_meta = #{}};
|
||||
encode_keyring_meta(#{
|
||||
current_key_id := CurrentKeyId,
|
||||
keys := KeysMeta
|
||||
}) ->
|
||||
EncodedKeysMeta = encode_keys_meta(KeysMeta),
|
||||
#'KeyringMeta'{current_key_id = CurrentKeyId, keys_meta = EncodedKeysMeta}.
|
||||
|
||||
|
||||
encode_keys_meta(undefined) ->
|
||||
undefined;
|
||||
encode_keys_meta(KeysMeta) ->
|
||||
maps:fold(
|
||||
fun (K, #{retired := Retired}, Acc) ->
|
||||
Acc#{K => #'KeyMeta'{retired = Retired}}
|
||||
end,
|
||||
#{},
|
||||
KeysMeta
|
||||
).
|
@ -7,10 +7,10 @@
|
||||
%% API
|
||||
-export([init/1, callback_mode/0]).
|
||||
-export([start_link/0]).
|
||||
-export([initialize/2]).
|
||||
-export([confirm/2]).
|
||||
-export([start_validation/0]).
|
||||
-export([validate/2]).
|
||||
-export([initialize/1]).
|
||||
-export([confirm/3]).
|
||||
-export([start_validation/1]).
|
||||
-export([validate/3]).
|
||||
-export([get_status/0]).
|
||||
-export([cancel/0]).
|
||||
-export([handle_event/4]).
|
||||
@ -22,8 +22,7 @@
|
||||
|
||||
-record(data, {
|
||||
threshold,
|
||||
encrypted_keyring,
|
||||
keyring,
|
||||
validation_keyring,
|
||||
shareholders,
|
||||
confirmation_shares = #{},
|
||||
validation_shares = #{},
|
||||
@ -45,6 +44,7 @@
|
||||
}.
|
||||
|
||||
-type encrypted_keyring() :: kds_keyring:encrypted_keyring().
|
||||
-type keyring() :: kds_keyring:keyring().
|
||||
|
||||
-type state() :: uninitialized | validation.
|
||||
|
||||
@ -66,30 +66,30 @@ callback_mode() -> handle_event_function.
|
||||
start_link() ->
|
||||
gen_statem:start_link({local, ?STATEM}, ?MODULE, [], []).
|
||||
|
||||
-spec initialize(threshold(), encrypted_keyring()) ->
|
||||
-spec initialize(threshold()) ->
|
||||
ok | {error, initialize_errors() | invalid_activity_errors()}.
|
||||
|
||||
initialize(Threshold, EncryptedKeyring) ->
|
||||
call({initialize, Threshold, EncryptedKeyring}).
|
||||
initialize(Threshold) ->
|
||||
call({initialize, Threshold}).
|
||||
|
||||
-spec confirm(shareholder_id(), masterkey_share()) ->
|
||||
{ok, {more, integer()}} | ok | {error, confirm_errors() | invalid_activity_errors()}.
|
||||
-spec confirm(shareholder_id(), masterkey_share(), encrypted_keyring()) ->
|
||||
{ok, {more, pos_integer()}} | ok | {error, confirm_errors() | invalid_activity_errors()}.
|
||||
|
||||
confirm(ShareholderId, Share) ->
|
||||
call({confirm, ShareholderId, Share}).
|
||||
confirm(ShareholderId, Share, EncryptedKeyring) ->
|
||||
call({confirm, ShareholderId, Share, EncryptedKeyring}).
|
||||
|
||||
-spec start_validation() -> {ok, encrypted_master_key_shares()} | {error, invalid_activity_errors()}.
|
||||
-spec start_validation(keyring()) -> {ok, encrypted_master_key_shares()} | {error, invalid_activity_errors()}.
|
||||
|
||||
start_validation() ->
|
||||
call(start_validatation).
|
||||
start_validation(Keyring) ->
|
||||
call({start_validatation, Keyring}).
|
||||
|
||||
-spec validate(shareholder_id(), masterkey_share()) ->
|
||||
{ok, {more, integer()}} |
|
||||
-spec validate(shareholder_id(), masterkey_share(), keyring()) ->
|
||||
{ok, {more, pos_integer()}} |
|
||||
{ok, {done, encrypted_keyring()}} |
|
||||
{error, validate_errors() | invalid_activity_errors()}.
|
||||
|
||||
validate(ShareholderId, Share) ->
|
||||
call({validate, ShareholderId, Share}).
|
||||
validate(ShareholderId, Share, Keyring) ->
|
||||
call({validate, ShareholderId, Share, Keyring}).
|
||||
|
||||
-spec cancel() -> ok.
|
||||
|
||||
@ -114,14 +114,13 @@ init([]) ->
|
||||
|
||||
%% Successful workflow events
|
||||
|
||||
handle_event({call, From}, {initialize, Threshold, EncryptedKeyring}, uninitialized, Data) ->
|
||||
handle_event({call, From}, {initialize, Threshold}, uninitialized, Data) ->
|
||||
Shareholders = kds_shareholder:get_all(),
|
||||
ShareholdersLength = length(Shareholders),
|
||||
case (Threshold >= 1) and (ShareholdersLength >= 1) and (Threshold =< ShareholdersLength) of
|
||||
true ->
|
||||
TimerRef = erlang:start_timer(get_timeout(), self(), lifetime_expired),
|
||||
NewData = Data#data{
|
||||
encrypted_keyring = EncryptedKeyring,
|
||||
threshold = Threshold,
|
||||
shareholders = Shareholders,
|
||||
timer = TimerRef},
|
||||
@ -135,15 +134,15 @@ handle_event({call, From}, {initialize, Threshold, EncryptedKeyring}, uninitiali
|
||||
#data{},
|
||||
{reply, From, {error, invalid_args}}}
|
||||
end;
|
||||
handle_event({call, From}, {confirm, ShareholderId, Share}, confirmation,
|
||||
#data{confirmation_shares = Shares, encrypted_keyring = EncryptedKeyring, timer = TimerRef} = Data) ->
|
||||
handle_event({call, From}, {confirm, ShareholderId, Share, EncryptedKeyring}, confirmation,
|
||||
#data{confirmation_shares = Shares, timer = TimerRef} = Data) ->
|
||||
#share{x = X, threshold = Threshold} = kds_keysharing:decode_share(Share),
|
||||
case Shares#{X => {ShareholderId, Share}} of
|
||||
AllShares when map_size(AllShares) =:= Threshold ->
|
||||
ListShares = kds_keysharing:get_shares(AllShares),
|
||||
case confirm_operation(EncryptedKeyring, ListShares) of
|
||||
{ok, Keyring} ->
|
||||
NewData = Data#data{confirmation_shares = AllShares, keyring = Keyring},
|
||||
ok ->
|
||||
NewData = Data#data{confirmation_shares = AllShares},
|
||||
{next_state,
|
||||
postconfirmation,
|
||||
NewData,
|
||||
@ -162,23 +161,23 @@ handle_event({call, From}, {confirm, ShareholderId, Share}, confirmation,
|
||||
NewData,
|
||||
{reply, From, {ok, {more, Threshold - maps:size(Shares1)}}}}
|
||||
end;
|
||||
handle_event({call, From}, start_validatation, postconfirmation,
|
||||
#data{shareholders = Shareholders, threshold = Threshold, keyring = Keyring} = Data) ->
|
||||
handle_event({call, From}, {start_validatation, Keyring}, postconfirmation,
|
||||
#data{shareholders = Shareholders, threshold = Threshold} = Data) ->
|
||||
MasterKey = kds_crypto:key(),
|
||||
EncryptedKeyring = kds_keyring:encrypt(MasterKey, Keyring),
|
||||
Shares = kds_keysharing:share(MasterKey, Threshold, length(Shareholders)),
|
||||
EncryptedShares = kds_keysharing:encrypt_shares_for_shareholders(Shares, Shareholders),
|
||||
NewData = Data#data{encrypted_keyring = EncryptedKeyring, keyring = undefined},
|
||||
NewData = Data#data{validation_keyring = EncryptedKeyring},
|
||||
{next_state,
|
||||
validation,
|
||||
NewData,
|
||||
{reply, From, {ok, EncryptedShares}}};
|
||||
handle_event({call, From}, {validate, ShareholderId, Share}, validation,
|
||||
handle_event({call, From}, {validate, ShareholderId, Share, Keyring}, validation,
|
||||
#data{
|
||||
shareholders = Shareholders,
|
||||
threshold = Threshold,
|
||||
validation_shares = Shares,
|
||||
encrypted_keyring = EncryptedKeyring,
|
||||
validation_keyring = ValidationKeyring,
|
||||
timer = TimerRef} = Data) ->
|
||||
#share{x = X} = kds_keysharing:decode_share(Share),
|
||||
ShareholdersCount = length(Shareholders),
|
||||
@ -186,7 +185,7 @@ handle_event({call, From}, {validate, ShareholderId, Share}, validation,
|
||||
AllShares when map_size(AllShares) =:= ShareholdersCount ->
|
||||
_Time = erlang:cancel_timer(TimerRef),
|
||||
ListShares = kds_keysharing:get_shares(AllShares),
|
||||
Result = validate_operation(Threshold, ListShares, EncryptedKeyring),
|
||||
Result = validate_operation(Threshold, ListShares, ValidationKeyring, Keyring),
|
||||
{next_state,
|
||||
uninitialized,
|
||||
#data{},
|
||||
@ -218,7 +217,7 @@ handle_event({call, From}, get_status, State,
|
||||
},
|
||||
{keep_state_and_data, {reply, From, Status}};
|
||||
handle_event({call, From}, cancel, _State, #data{timer = TimerRef}) ->
|
||||
_ = erlang:cancel_timer(TimerRef),
|
||||
ok = cancel_timer(TimerRef),
|
||||
{next_state, uninitialized, #data{}, {reply, From, ok}};
|
||||
handle_event(info, {timeout, _TimerRef, lifetime_expired}, _State, _Data) ->
|
||||
{next_state, uninitialized, #data{}, []};
|
||||
@ -257,15 +256,14 @@ get_lifetime(TimerRef) ->
|
||||
erlang:read_timer(TimerRef) div 1000
|
||||
end.
|
||||
|
||||
-spec confirm_operation(encrypted_keyring(), masterkey_shares()) ->
|
||||
{ok, kds_keyring:keyring()} | {error, confirm_errors()}.
|
||||
-spec confirm_operation(encrypted_keyring(), masterkey_shares()) -> ok | {error, confirm_errors()}.
|
||||
|
||||
confirm_operation(EncryptedOldKeyring, AllShares) ->
|
||||
case kds_keysharing:recover(AllShares) of
|
||||
{ok, MasterKey} ->
|
||||
case kds_keyring:validate_masterkey(MasterKey, EncryptedOldKeyring) of
|
||||
{ok, Keyring} ->
|
||||
{ok, Keyring};
|
||||
{ok, _Keyring} ->
|
||||
ok;
|
||||
{error, wrong_masterkey} ->
|
||||
{error, {operation_aborted, wrong_masterkey}}
|
||||
end;
|
||||
@ -273,14 +271,15 @@ confirm_operation(EncryptedOldKeyring, AllShares) ->
|
||||
{error, {operation_aborted, failed_to_recover}}
|
||||
end.
|
||||
|
||||
-spec validate_operation(threshold(), masterkey_shares(), encrypted_keyring()) ->
|
||||
-spec validate_operation(threshold(), masterkey_shares(), encrypted_keyring(), keyring()) ->
|
||||
{ok, {done, encrypted_keyring()}} | {error, validate_errors()}.
|
||||
|
||||
validate_operation(Threshold, Shares, EncryptedKeyring) ->
|
||||
validate_operation(Threshold, Shares, ValidationKeyring, Keyring) ->
|
||||
case kds_keysharing:validate_shares(Threshold, Shares) of
|
||||
{ok, MasterKey} ->
|
||||
case kds_keyring:decrypt(MasterKey, EncryptedKeyring) of
|
||||
case kds_keyring:decrypt(MasterKey, ValidationKeyring) of
|
||||
{ok, _DecryptedKeyring} ->
|
||||
EncryptedKeyring = kds_keyring:encrypt(MasterKey, Keyring),
|
||||
{ok, {done, EncryptedKeyring}};
|
||||
{error, decryption_failed} ->
|
||||
{error, {operation_aborted, failed_to_decrypt_keyring}}
|
||||
@ -288,3 +287,9 @@ validate_operation(Threshold, Shares, EncryptedKeyring) ->
|
||||
{error, Error} ->
|
||||
{error, {operation_aborted, Error}}
|
||||
end.
|
||||
|
||||
cancel_timer(undefined) ->
|
||||
ok;
|
||||
cancel_timer(TimerRef) ->
|
||||
_ = erlang:cancel_timer(TimerRef),
|
||||
ok.
|
||||
|
@ -10,8 +10,8 @@
|
||||
-export([init/1, callback_mode/0]).
|
||||
|
||||
-export([start_link/0]).
|
||||
-export([initialize/2]).
|
||||
-export([confirm/2]).
|
||||
-export([initialize/0]).
|
||||
-export([confirm/4]).
|
||||
-export([get_status/0]).
|
||||
-export([cancel/0]).
|
||||
-export([handle_event/4]).
|
||||
@ -19,8 +19,6 @@
|
||||
-export_type([state/0]).
|
||||
|
||||
-record(data, {
|
||||
encrypted_keyring :: encrypted_keyring() | undefined,
|
||||
keyring :: keyring() | undefined,
|
||||
shares = #{} :: #{kds_keysharing:share_id() => {shareholder_id(), masterkey_share()}},
|
||||
timer :: reference() | undefined
|
||||
}).
|
||||
@ -45,7 +43,7 @@
|
||||
-type invalid_activity() :: {error, {invalid_activity, {rotation, state()}}}.
|
||||
-type rotate_resp() ::
|
||||
{ok, {done, {encrypted_keyring(), keyring()}}} |
|
||||
{ok, {more, non_neg_integer()}}|
|
||||
{ok, {more, pos_integer()}}|
|
||||
{error, {operation_aborted, rotate_errors()}}.
|
||||
|
||||
-spec callback_mode() -> handle_event_function.
|
||||
@ -57,15 +55,16 @@ callback_mode() -> handle_event_function.
|
||||
start_link() ->
|
||||
gen_statem:start_link({local, ?STATEM}, ?MODULE, [], []).
|
||||
|
||||
-spec initialize(keyring(), encrypted_keyring()) -> ok | invalid_activity().
|
||||
-spec initialize() -> ok | invalid_activity().
|
||||
|
||||
initialize(Keyring, EncryptedKeyring) ->
|
||||
call({initialize, Keyring, EncryptedKeyring}).
|
||||
initialize() ->
|
||||
call(initialize).
|
||||
|
||||
-spec confirm(shareholder_id(), masterkey_share()) -> rotate_resp() | invalid_activity().
|
||||
-spec confirm(shareholder_id(), masterkey_share(), encrypted_keyring(), keyring()) ->
|
||||
rotate_resp() | invalid_activity().
|
||||
|
||||
confirm(ShareholderId, Share) ->
|
||||
call({confirm, ShareholderId, Share}).
|
||||
confirm(ShareholderId, Share, EncryptedOldKeyring, OldKeyring) ->
|
||||
call({confirm, ShareholderId, Share, EncryptedOldKeyring, OldKeyring}).
|
||||
|
||||
-spec cancel() -> ok.
|
||||
|
||||
@ -90,17 +89,14 @@ init([]) ->
|
||||
|
||||
%% Successful workflow events
|
||||
|
||||
handle_event({call, From}, {initialize, Keyring, EncryptedKeyring}, uninitialized, _Data) ->
|
||||
handle_event({call, From}, initialize, uninitialized, _Data) ->
|
||||
TimerRef = erlang:start_timer(get_timeout(), self(), lifetime_expired),
|
||||
{next_state,
|
||||
validation,
|
||||
#data{keyring = Keyring, encrypted_keyring = EncryptedKeyring, timer = TimerRef}, {reply, From, ok}};
|
||||
#data{timer = TimerRef}, {reply, From, ok}};
|
||||
|
||||
handle_event({call, From}, {confirm, ShareholderId, Share}, validation,
|
||||
#data{encrypted_keyring = EncryptedOldKeyring,
|
||||
keyring = OldKeyring,
|
||||
shares = Shares,
|
||||
timer = TimerRef} = StateData) ->
|
||||
handle_event({call, From}, {confirm, ShareholderId, Share, EncryptedOldKeyring, OldKeyring}, validation,
|
||||
#data{shares = Shares, timer = TimerRef} = StateData) ->
|
||||
#share{threshold = Threshold, x = X} = kds_keysharing:decode_share(Share),
|
||||
case Shares#{X => {ShareholderId, Share}} of
|
||||
AllShares when map_size(AllShares) =:= Threshold ->
|
||||
@ -128,7 +124,7 @@ handle_event({call, From}, get_status, State, #data{timer = TimerRef, shares = V
|
||||
},
|
||||
{keep_state_and_data, {reply, From, Status}};
|
||||
handle_event({call, From}, cancel, _State, #data{timer = TimerRef}) ->
|
||||
_ = erlang:cancel_timer(TimerRef),
|
||||
ok = cancel_timer(TimerRef),
|
||||
{next_state, uninitialized, #data{}, {reply, From, ok}};
|
||||
handle_event(info, {timeout, _TimerRef, lifetime_expired}, _State, _Data) ->
|
||||
{next_state, uninitialized, #data{}, []};
|
||||
@ -176,3 +172,9 @@ update_keyring(OldKeyring, EncryptedOldKeyring, AllShares) ->
|
||||
{error, Error} ->
|
||||
{error, {operation_aborted, Error}}
|
||||
end.
|
||||
|
||||
cancel_timer(undefined) ->
|
||||
ok;
|
||||
cancel_timer(TimerRef) ->
|
||||
_ = erlang:cancel_timer(TimerRef),
|
||||
ok.
|
||||
|
@ -1,9 +1,9 @@
|
||||
-module(kds_keyring_storage).
|
||||
|
||||
-callback child_spec(map()) -> {ok, supervisor:child_spec()}.
|
||||
-callback create(binary()) -> ok | {error, already_exists}.
|
||||
-callback read() -> {ok, binary()} | {error, not_found}.
|
||||
-callback update(binary()) -> ok.
|
||||
-callback create(kds_keyring:encrypted_keyring()) -> ok | {error, already_exists}.
|
||||
-callback read() -> {ok, kds_keyring:encrypted_keyring()} | {error, not_found}.
|
||||
-callback update(kds_keyring:encrypted_keyring()) -> ok.
|
||||
-callback delete() -> ok.
|
||||
|
||||
-export([child_spec/1]).
|
||||
@ -16,15 +16,15 @@
|
||||
child_spec(StorageOpts) ->
|
||||
kds_backend:call(keyring_storage, child_spec, [StorageOpts]).
|
||||
|
||||
-spec create(binary()) -> ok.
|
||||
-spec create(kds_keyring:encrypted_keyring()) -> ok.
|
||||
create(Keyring) ->
|
||||
kds_backend:call(keyring_storage, create, [Keyring]).
|
||||
|
||||
-spec read() -> binary().
|
||||
-spec read() -> kds_keyring:encrypted_keyring().
|
||||
read() ->
|
||||
kds_backend:call(keyring_storage, read, []).
|
||||
|
||||
-spec update(binary()) -> ok.
|
||||
-spec update(kds_keyring:encrypted_keyring()) -> ok.
|
||||
update(Keyring) ->
|
||||
kds_backend:call(keyring_storage, update, [Keyring]).
|
||||
|
||||
|
@ -12,6 +12,7 @@
|
||||
|
||||
-define(SERVER, ?MODULE).
|
||||
-define(DEFAULT_KEYRING_PATH, "/var/lib/kds/keyring").
|
||||
-define(FORMAT_VERSION, 1).
|
||||
|
||||
-record(state, {
|
||||
keyring_path :: string()
|
||||
@ -30,15 +31,15 @@ child_spec(StorageOpts) ->
|
||||
start_link(KeyringPath) ->
|
||||
gen_server:start_link({local, ?SERVER}, ?MODULE, KeyringPath, []).
|
||||
|
||||
-spec create(binary()) -> ok | {error, already_exists}.
|
||||
-spec create(kds_keyring:encrypted_keyring()) -> ok | {error, already_exists}.
|
||||
create(Keyring) ->
|
||||
gen_server:call(?SERVER, {create, Keyring}).
|
||||
|
||||
-spec read() -> {ok, binary()} | {error, not_found}.
|
||||
-spec read() -> {ok, kds_keyring:encrypted_keyring()} | {error, not_found}.
|
||||
read() ->
|
||||
gen_server:call(?SERVER, read).
|
||||
|
||||
-spec update(binary()) -> ok.
|
||||
-spec update(kds_keyring:encrypted_keyring()) -> ok.
|
||||
update(Keyring) ->
|
||||
gen_server:call(?SERVER, {update, Keyring}).
|
||||
|
||||
@ -54,8 +55,11 @@ init(KeyringPath) ->
|
||||
handle_call({create, Keyring}, _From, #state{keyring_path = KeyringPath} = State) ->
|
||||
Reply = case filelib:is_regular(KeyringPath) of
|
||||
false ->
|
||||
KeyringWithFormat = Keyring#{
|
||||
format_version => ?FORMAT_VERSION
|
||||
},
|
||||
ok = filelib:ensure_dir(KeyringPath),
|
||||
ok = atomic_write(KeyringPath, Keyring);
|
||||
ok = atomic_write(KeyringPath, jsx:encode(KeyringWithFormat));
|
||||
true ->
|
||||
{error, already_exists}
|
||||
end,
|
||||
@ -63,14 +67,24 @@ handle_call({create, Keyring}, _From, #state{keyring_path = KeyringPath} = State
|
||||
handle_call(read, _From, #state{keyring_path = KeyringPath} = State) ->
|
||||
Reply = case file:read_file(KeyringPath) of
|
||||
{ok, Data} ->
|
||||
{ok, Data};
|
||||
case jsx:is_json(Data) of
|
||||
true ->
|
||||
DecodedData = decode_encrypted_keyring(
|
||||
jsx:decode(Data, [return_maps, {labels, binary}])),
|
||||
{ok, #{data => maps:get(data, DecodedData), meta => maps:get(meta, DecodedData)}};
|
||||
false ->
|
||||
{ok, #{data => Data, meta => undefined}}
|
||||
end;
|
||||
{error, enoent} ->
|
||||
{error, not_found}
|
||||
end,
|
||||
{reply, Reply, State};
|
||||
handle_call({update, Keyring}, _From, #state{keyring_path = KeyringPath} = State) ->
|
||||
KeyringWithFormat = Keyring#{
|
||||
format_version => ?FORMAT_VERSION
|
||||
},
|
||||
ok = filelib:ensure_dir(KeyringPath),
|
||||
ok = atomic_write(KeyringPath, Keyring),
|
||||
ok = atomic_write(KeyringPath, jsx:encode(KeyringWithFormat)),
|
||||
{reply, ok, State};
|
||||
handle_call(delete, _From, #state{keyring_path = KeyringPath} = State) ->
|
||||
_ = case file:delete(KeyringPath) of
|
||||
@ -87,8 +101,39 @@ handle_cast(_Request, State) ->
|
||||
|
||||
atomic_write(Path, Keyring) ->
|
||||
TmpPath = tmp_keyring_path(Path),
|
||||
ok = file:write_file(TmpPath, Keyring),
|
||||
ok = file:write_file(TmpPath, Keyring, [sync]),
|
||||
file:rename(TmpPath, Path).
|
||||
|
||||
tmp_keyring_path(Path) ->
|
||||
genlib:to_list(Path) ++ ".tmp".
|
||||
|
||||
-spec decode_encrypted_keyring(map()) -> kds_keyring:encrypted_keyring().
|
||||
decode_encrypted_keyring(#{
|
||||
<<"format_version">> := 1,
|
||||
<<"data">> := KeyringData,
|
||||
<<"meta">> := #{
|
||||
<<"current_key_id">> := CurrentKeyId,
|
||||
<<"version">> := Version,
|
||||
<<"keys">> := KeysMeta
|
||||
}
|
||||
})->
|
||||
#{
|
||||
data => KeyringData,
|
||||
meta => #{
|
||||
current_key_id => CurrentKeyId,
|
||||
version => Version,
|
||||
keys => decode_number_key_map(KeysMeta)
|
||||
}
|
||||
}.
|
||||
|
||||
decode_number_key_map(Map) ->
|
||||
maps:fold(
|
||||
fun (K, #{<<"retired">> := Retired}, Acc) ->
|
||||
Acc#{
|
||||
binary_to_integer(K) => #{
|
||||
retired => Retired
|
||||
}
|
||||
}
|
||||
end,
|
||||
#{},
|
||||
Map).
|
||||
|
62
apps/kds/src/kds_keyring_storage_thrift_handler.erl
Normal file
62
apps/kds/src/kds_keyring_storage_thrift_handler.erl
Normal file
@ -0,0 +1,62 @@
|
||||
-module(kds_keyring_storage_thrift_handler).
|
||||
-behaviour(woody_server_thrift_handler).
|
||||
|
||||
-include_lib("cds_proto/include/cds_proto_keyring_thrift.hrl").
|
||||
|
||||
%% woody_server_thrift_handler callbacks
|
||||
-export([handle_function/4]).
|
||||
|
||||
%%
|
||||
%% woody_server_thrift_handler callbacks
|
||||
%%
|
||||
|
||||
-spec handle_function(woody:func(), woody:args(), woody_context:ctx(), woody:options()) ->
|
||||
{ok, woody:result()} | no_return().
|
||||
|
||||
handle_function(OperationID, Args, Context, Opts) ->
|
||||
scoper:scope(
|
||||
keyring_storage,
|
||||
fun() -> handle_function_(OperationID, Args, Context, Opts) end
|
||||
).
|
||||
|
||||
handle_function_('GetKeyring', [], _Context, _Opts) ->
|
||||
try kds_keyring_manager:get_keyring() of
|
||||
Keyring ->
|
||||
{ok, encode_keyring(Keyring)}
|
||||
catch
|
||||
{invalid_status, Status} ->
|
||||
raise(#'InvalidStatus'{status = Status})
|
||||
end.
|
||||
|
||||
encode_keyring(#{
|
||||
data := #{
|
||||
keys := Keys
|
||||
},
|
||||
meta := #{
|
||||
current_key_id := CurrentKeyId,
|
||||
version := Version,
|
||||
keys := KeysMeta
|
||||
}
|
||||
}) ->
|
||||
#'Keyring'{
|
||||
version = Version,
|
||||
current_key_id = CurrentKeyId,
|
||||
keys = encode_keys(Keys, KeysMeta)
|
||||
}.
|
||||
|
||||
encode_keys(Keys, KeysMeta) ->
|
||||
maps:fold(
|
||||
fun(K, V, Acc) ->
|
||||
#{retired := Retired} = maps:get(K, KeysMeta),
|
||||
Acc#{K => #'Key'{
|
||||
data = V,
|
||||
meta = #'KeyMeta'{
|
||||
retired = Retired
|
||||
}
|
||||
}}
|
||||
end,
|
||||
#{}, Keys).
|
||||
|
||||
-spec raise(_) -> no_return().
|
||||
raise(Exception) ->
|
||||
woody_error:raise(business, Exception).
|
@ -10,8 +10,8 @@
|
||||
-export([init/1, callback_mode/0]).
|
||||
|
||||
-export([start_link/0]).
|
||||
-export([initialize/1]).
|
||||
-export([confirm/2]).
|
||||
-export([initialize/0]).
|
||||
-export([confirm/3]).
|
||||
-export([get_status/0]).
|
||||
-export([cancel/0]).
|
||||
-export([handle_event/4]).
|
||||
@ -19,9 +19,8 @@
|
||||
-export_type([state/0]).
|
||||
|
||||
-record(data, {
|
||||
locked_keyring,
|
||||
shares = #{},
|
||||
timer
|
||||
shares = #{} :: #{kds_keysharing:share_id() => {shareholder_id(), masterkey_share()}},
|
||||
timer :: reference() | undefined
|
||||
}).
|
||||
|
||||
-type data() :: #data{}.
|
||||
@ -37,14 +36,14 @@
|
||||
-type shareholder_id() :: kds_shareholder:shareholder_id().
|
||||
-type masterkey_share() :: kds_keysharing:masterkey_share().
|
||||
-type masterkey_shares() :: kds_keysharing:masterkey_shares().
|
||||
-type keyring() :: kds_keyring:keyring().
|
||||
-type locked_keyring() :: kds_keyring:encrypted_keyring().
|
||||
-type keyring() :: kds_keyring:keyring().
|
||||
-type unlock_errors() ::
|
||||
wrong_masterkey | failed_to_recover.
|
||||
-type invalid_activity() :: {error, {invalid_activity, {unlock, state()}}}.
|
||||
-type unlock_resp() ::
|
||||
{ok, {done, keyring()}} |
|
||||
{ok, {more, non_neg_integer()}}|
|
||||
{ok, {more, pos_integer()}} |
|
||||
{error, {operation_aborted, unlock_errors()}}.
|
||||
|
||||
-spec callback_mode() -> handle_event_function.
|
||||
@ -56,15 +55,15 @@ callback_mode() -> handle_event_function.
|
||||
start_link() ->
|
||||
gen_statem:start_link({local, ?STATEM}, ?MODULE, [], []).
|
||||
|
||||
-spec initialize(locked_keyring()) -> ok | invalid_activity().
|
||||
-spec initialize() -> ok | invalid_activity().
|
||||
|
||||
initialize(LockedKeyring) ->
|
||||
call({initialize, LockedKeyring}).
|
||||
initialize() ->
|
||||
call(initialize).
|
||||
|
||||
-spec confirm(shareholder_id(), masterkey_share()) -> unlock_resp() | invalid_activity().
|
||||
-spec confirm(shareholder_id(), masterkey_share(), locked_keyring()) -> unlock_resp() | invalid_activity().
|
||||
|
||||
confirm(ShareholderId, Share) ->
|
||||
call({confirm, ShareholderId, Share}).
|
||||
confirm(ShareholderId, Share, LockedKeyring) ->
|
||||
call({confirm, ShareholderId, Share, LockedKeyring}).
|
||||
|
||||
-spec cancel() -> ok.
|
||||
|
||||
@ -89,15 +88,15 @@ init([]) ->
|
||||
|
||||
%% Successful workflow events
|
||||
|
||||
handle_event({call, From}, {initialize, LockedKeyring}, uninitialized, _Data) ->
|
||||
handle_event({call, From}, initialize, uninitialized, _Data) ->
|
||||
TimerRef = erlang:start_timer(get_timeout(), self(), lifetime_expired),
|
||||
{next_state,
|
||||
validation,
|
||||
#data{locked_keyring = LockedKeyring, timer = TimerRef},
|
||||
#data{timer = TimerRef},
|
||||
{reply, From, ok}};
|
||||
|
||||
handle_event({call, From}, {confirm, ShareholderId, Share}, validation,
|
||||
#data{locked_keyring = LockedKeyring, shares = Shares, timer = TimerRef} = StateData) ->
|
||||
handle_event({call, From}, {confirm, ShareholderId, Share, LockedKeyring}, validation,
|
||||
#data{shares = Shares, timer = TimerRef} = StateData) ->
|
||||
#share{threshold = Threshold, x = X} = kds_keysharing:decode_share(Share),
|
||||
case Shares#{X => {ShareholderId, Share}} of
|
||||
AllShares when map_size(AllShares) =:= Threshold ->
|
||||
@ -127,7 +126,7 @@ handle_event({call, From}, get_status, State, #data{timer = TimerRef, shares = V
|
||||
},
|
||||
{keep_state_and_data, {reply, From, Status}};
|
||||
handle_event({call, From}, cancel, _State, #data{timer = TimerRef}) ->
|
||||
_ = erlang:cancel_timer(TimerRef),
|
||||
ok = cancel_timer(TimerRef),
|
||||
{next_state, uninitialized, #data{}, {reply, From, ok}};
|
||||
handle_event(info, {timeout, _TimerRef, lifetime_expired}, _State, _Data) ->
|
||||
{next_state, uninitialized, #data{}, []};
|
||||
@ -173,3 +172,9 @@ unlock(LockedKeyring, AllShares) ->
|
||||
{error, Error} ->
|
||||
{error, {operation_aborted, Error}}
|
||||
end.
|
||||
|
||||
cancel_timer(undefined) ->
|
||||
ok;
|
||||
cancel_timer(TimerRef) ->
|
||||
_ = erlang:cancel_timer(TimerRef),
|
||||
ok.
|
||||
|
@ -8,7 +8,7 @@
|
||||
%% Types
|
||||
%%
|
||||
|
||||
-type service_name() :: keyring_v2.
|
||||
-type service_name() :: keyring_management | keyring_storage.
|
||||
|
||||
-export_type([service_name/0]).
|
||||
|
||||
@ -21,13 +21,19 @@ http_handler(Code) ->
|
||||
{path(Code), {service(Code), handler_module(Code)}}.
|
||||
|
||||
-spec path(service_name()) -> woody:path().
|
||||
path(keyring_v2) ->
|
||||
"/v2/keyring".
|
||||
path(keyring_management) ->
|
||||
"/v2/keyring";
|
||||
path(keyring_storage) ->
|
||||
"/v2/keyring_storage".
|
||||
|
||||
-spec service(service_name()) -> woody:service().
|
||||
service(keyring_v2) ->
|
||||
{cds_proto_keyring_thrift, 'Keyring'}.
|
||||
service(keyring_management) ->
|
||||
{cds_proto_keyring_thrift, 'KeyringManagement'};
|
||||
service(keyring_storage) ->
|
||||
{cds_proto_keyring_thrift, 'KeyringStorage'}.
|
||||
|
||||
-spec handler_module(service_name()) -> woody:handler(list()).
|
||||
handler_module(keyring_v2) ->
|
||||
{kds_keyring_v2_thrift_handler, []}.
|
||||
handler_module(keyring_management) ->
|
||||
{kds_keyring_management_thrift_handler, []};
|
||||
handler_module(keyring_storage) ->
|
||||
{kds_keyring_storage_thrift_handler, []}.
|
||||
|
@ -109,7 +109,7 @@ config(Key, Config, Default) ->
|
||||
end.
|
||||
|
||||
root_url(C) ->
|
||||
config(root_url, C).
|
||||
config(management_root_url, C).
|
||||
|
||||
enc_private_keys(C) ->
|
||||
config(enc_private_keys, C).
|
||||
|
@ -26,20 +26,35 @@
|
||||
-spec start_clear(config()) -> config().
|
||||
start_clear(Config) ->
|
||||
IP = "127.0.0.1",
|
||||
Port = 8022,
|
||||
RootUrl = "http://" ++ IP ++ ":" ++ integer_to_list(Port),
|
||||
ManagementPort = 8022,
|
||||
StoragePort = 8023,
|
||||
ManagementRootUrl = "http://" ++ IP ++ ":" ++ integer_to_list(ManagementPort),
|
||||
StorageRootUrl = "https://" ++ IP ++ ":" ++ integer_to_list(StoragePort),
|
||||
CACertFile = filename:join(config(data_dir, Config), "ca.crt"),
|
||||
ServerCertFile = filename:join(config(data_dir, Config), "server.pem"),
|
||||
ClientCertFile = filename:join(config(data_dir, Config), "client.pem"),
|
||||
Apps =
|
||||
genlib_app:start_application_with(scoper, [
|
||||
{storage, scoper_storage_logger}
|
||||
]) ++
|
||||
genlib_app:start_application_with(kds, [
|
||||
{ip, IP},
|
||||
{port, Port},
|
||||
{management_port, ManagementPort},
|
||||
{storage_port, StoragePort},
|
||||
{keyring_storage, kds_keyring_storage_file},
|
||||
{keyring_storage_opts, #{
|
||||
keyring_path => filename:join(config(priv_dir, Config), "keyring")
|
||||
}},
|
||||
{transport_opts, #{}},
|
||||
{management_transport_opts, #{}},
|
||||
{storage_transport_opts, #{
|
||||
transport => ranch_ssl,
|
||||
socket_opts => [
|
||||
{cacertfile, CACertFile},
|
||||
{certfile, ServerCertFile},
|
||||
{verify, verify_peer},
|
||||
{fail_if_no_peer_cert, true}
|
||||
]
|
||||
}},
|
||||
{protocol_opts, #{
|
||||
request_timeout => 60000
|
||||
}},
|
||||
@ -107,7 +122,10 @@ start_clear(Config) ->
|
||||
]),
|
||||
[
|
||||
{apps, lists:reverse(Apps)},
|
||||
{root_url, genlib:to_binary(RootUrl)}
|
||||
{management_root_url, genlib:to_binary(ManagementRootUrl)},
|
||||
{storage_root_url, genlib:to_binary(StorageRootUrl)},
|
||||
{cacertfile, CACertFile},
|
||||
{clientcertfile, ClientCertFile}
|
||||
] ++ Config.
|
||||
|
||||
-spec stop_clear(config()) -> ok.
|
||||
|
@ -42,7 +42,7 @@
|
||||
%% tests descriptions
|
||||
%%
|
||||
|
||||
-type config() :: term().
|
||||
-type config() :: [tuple()].
|
||||
|
||||
-spec test() -> _.
|
||||
|
||||
@ -257,6 +257,10 @@ unlock(C) ->
|
||||
[{Id1, MasterKey1}, {Id2, MasterKey2}, _MasterKey3] = kds_ct_utils:lookup(master_keys, C),
|
||||
_ = ?assertEqual(ok, kds_keyring_client:start_unlock(root_url(C))),
|
||||
_ = ?assertEqual({more_keys_needed, 1}, kds_keyring_client:confirm_unlock(Id1, MasterKey1, root_url(C))),
|
||||
_ = ?assertEqual(
|
||||
{error, {invalid_activity, {unlock, validation}}},
|
||||
kds_keyring_client:start_unlock(root_url(C))
|
||||
),
|
||||
State = kds_keyring_client:get_state(root_url(C)),
|
||||
_ = ?assertMatch(
|
||||
#{
|
||||
@ -289,6 +293,10 @@ unlock_with_timeout(C) ->
|
||||
_ = ?assertEqual({more_keys_needed, 1}, kds_keyring_client:confirm_unlock(Id1, MasterKey1, root_url(C))),
|
||||
Timeout = genlib_app:env(kds, keyring_unlock_lifetime, 1000),
|
||||
timer:sleep(Timeout + 500),
|
||||
_ = ?assertEqual(
|
||||
{error, {invalid_activity, {unlock, uninitialized}}},
|
||||
kds_keyring_client:confirm_unlock(Id1, MasterKey1, root_url(C))
|
||||
),
|
||||
_ = ?assertEqual(ok, kds_keyring_client:start_unlock(root_url(C))),
|
||||
_ = ?assertEqual({more_keys_needed, 1}, kds_keyring_client:confirm_unlock(Id1, MasterKey1, root_url(C))),
|
||||
_ = ?assertEqual(ok, kds_keyring_client:confirm_unlock(Id2, MasterKey2, root_url(C))).
|
||||
@ -381,10 +389,14 @@ rekey_with_timeout(C) ->
|
||||
-spec rekey_with_cancel(config()) -> _.
|
||||
|
||||
rekey_with_cancel(C) ->
|
||||
[{Id1, MasterKey1}, {Id2, MasterKey2}, _MasterKey3] = kds_ct_utils:lookup(master_keys, C),
|
||||
_ = ?assertEqual(
|
||||
{error, {invalid_activity, {rekeying, uninitialized}}},
|
||||
kds_keyring_client:confirm_rekey(Id1, MasterKey1, root_url(C))
|
||||
),
|
||||
_ = ?assertEqual(ok, kds_keyring_client:start_rekey(2, root_url(C))),
|
||||
_ = ?assertEqual(ok, kds_keyring_client:cancel_rekey(root_url(C))),
|
||||
_ = ?assertEqual(ok, kds_keyring_client:start_rekey(2, root_url(C))),
|
||||
[{Id1, MasterKey1}, {Id2, MasterKey2}, _MasterKey3] = kds_ct_utils:lookup(master_keys, C),
|
||||
_ = ?assertEqual(
|
||||
{more_keys_needed, 1},
|
||||
kds_keyring_client:confirm_rekey(Id1, MasterKey1, root_url(C))
|
||||
@ -422,7 +434,15 @@ validate_rekey([{Id, DecryptedMasterKeyShare} | DecryptedMasterKeyShares], C) ->
|
||||
|
||||
rotate(C) ->
|
||||
[{Id1, MasterKey1}, {Id2, MasterKey2}, _MasterKey3] = kds_ct_utils:lookup(master_keys, C),
|
||||
_ = ?assertEqual(
|
||||
{error, {invalid_activity, {rotation, uninitialized}}},
|
||||
kds_keyring_client:confirm_rotate(Id1, MasterKey1, root_url(C))
|
||||
),
|
||||
_ = ?assertEqual(ok, kds_keyring_client:start_rotate(root_url(C))),
|
||||
_ = ?assertEqual(
|
||||
{error, {invalid_activity, {rotation, confirmation}}},
|
||||
kds_keyring_client:start_rotate(root_url(C))
|
||||
),
|
||||
_ = ?assertEqual({more_keys_needed, 1}, kds_keyring_client:confirm_rotate(Id1, MasterKey1, root_url(C))),
|
||||
_ = ?assertEqual(ok, kds_keyring_client:confirm_rotate(Id2, MasterKey2, root_url(C))).
|
||||
|
||||
@ -723,7 +743,7 @@ config(Key, Config, Default) ->
|
||||
end.
|
||||
|
||||
root_url(C) ->
|
||||
config(root_url, C).
|
||||
config(management_root_url, C).
|
||||
|
||||
enc_private_keys(C) ->
|
||||
config(enc_private_keys, C).
|
||||
|
33
apps/kds/test/kds_keyring_api_tests_SUITE_data/ca.crt
Normal file
33
apps/kds/test/kds_keyring_api_tests_SUITE_data/ca.crt
Normal file
@ -0,0 +1,33 @@
|
||||
-----BEGIN CERTIFICATE-----
|
||||
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
|
||||
-----END CERTIFICATE-----
|
82
apps/kds/test/kds_keyring_api_tests_SUITE_data/client.pem
Normal file
82
apps/kds/test/kds_keyring_api_tests_SUITE_data/client.pem
Normal file
@ -0,0 +1,82 @@
|
||||
-----BEGIN CERTIFICATE-----
|
||||
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
|
||||
-----END CERTIFICATE-----
|
||||
-----BEGIN RSA PRIVATE KEY-----
|
||||
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
|
||||
-----END RSA PRIVATE KEY-----
|
82
apps/kds/test/kds_keyring_api_tests_SUITE_data/server.pem
Normal file
82
apps/kds/test/kds_keyring_api_tests_SUITE_data/server.pem
Normal file
@ -0,0 +1,82 @@
|
||||
-----BEGIN CERTIFICATE-----
|
||||
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
|
||||
-----END CERTIFICATE-----
|
||||
-----BEGIN RSA PRIVATE KEY-----
|
||||
MIIJKAIBAAKCAgEAozneAZhRIFqBCsdwdvufV7El2eB1ylKjr203ruk7L8mCcYCy
|
||||
ngmqXwNuV05RrTbXaLju9KWi+Kub7weLE3k1PWGuFmBJpzdX0tGa5D7DfB3n3oYp
|
||||
5PZA/pvZ1NF+070oIkxct8EDwqiepRmINEgexcbocfusD/ifpwkxucH/+/GQJeEz
|
||||
2uApLetwv5A9cTRuPBbuCcvnY5+hjQ5eCLqHRlImwburtaHXVs0oI2YMytZlifZ2
|
||||
mHtu+nduN3ni/HdVME19Y1U94GQUAjGrbcncj1IOt5B9w+MQSRxtgNmvUzHw275o
|
||||
3DL6bITz3kRo0N5jkERtdmsFmifg7UKD8fw9PXplres3s8fPcrF0ZY/ARk38n282
|
||||
olrt329Q7l9lZUMiB+6DyjFcDypv3t7ubD1N/6He65v6jyqmcHISOQ6zzG9FA7fc
|
||||
0WwRB9W83wTgY8nu+oSsFQWl/KM8sVNDGXgImtRn3k/Vhs04k0YwvrA0mWtYFIZU
|
||||
vxevFH0lQnLaVFB1QGDvj1ZaDN4TnAYbCJhQfmIL21LS0FBCv9KDOmtkmD4a0Y6R
|
||||
IJ6b6FVq8NeYlqCSAhn+Rw0tmpfmr9BTyaeIxHgzUMjAOttkwluc5SR0xYJESB9d
|
||||
7Hu1FGtvX1H86i0dxkDmavSNMfLN+QPyCiTcu2fevOVQgrWqagV3If9rRLMCAwEA
|
||||
AQKCAgAp/Iao7l9f7Sfod+jsEkmoqv7Ljrt98cf9JiD+syvwXOta+vn3QRE8I4vM
|
||||
lW7ZGZRLcda1w62qPap8z/nsZm9VfLzlMJuBkfDbX+Nx9tseICs2yFgad2W8mKZt
|
||||
4f23xZ5/RBlNgy7OccVtPqYUnMCdq067kzttWEzpEKpj2A1a54Zm2AkYsjSlhTyZ
|
||||
aicD6bK5bkSI7JR2wecye5GguSp24kbp6rZ+oETeJSPAB04fFwtDc8yJ6KZhczs8
|
||||
tfO3cZLOPACW/qROBjBHaDNqqFQ94aO7gEV5j/zucYuRa213/w6v18jta4eTRpfc
|
||||
gshbgfkmcROfNGRahQuMvGFoa7PspVWiRHtV20Sbjh+sHDFdVQHKV1Gfy09QLpdE
|
||||
e0p3k+yw/TJAGYZcWCSRaEHTm2Z8lV8LYm8xUtcrl85ypxsp8G1Q81o6Pkzl/OQh
|
||||
X0NQdwnmfcTAHUW5U7j7mmoNZzkoG+SadinH3M3LKq+3uQlMy7uhd/+Fd0QlTzjj
|
||||
Xw0O7LjM/KTZ6KmHEgLHg/WlM3oNQmK6/qc6swGz5o0q0zQT9E6qPSDzqH8cwa23
|
||||
jDF8SMEzXToCUqR2REN5jhybevqTuWPeOTPOXXFQUNvh4in+95u54TkgvsHjUIZe
|
||||
wp7E3Mtb81u6GTEct7ZLZTINFlLrGrmB4ZmnkVTHTg0qJDk5QQKCAQEAzp878HlT
|
||||
WJvXRtsIDr2gyUJUW/oAPQj5btvpEiRMDN1XTFBSUs/+GSXd9Rm5CQah/b0FVeo2
|
||||
sEEBz3iIHLKGvVyeDQ3L4FWzBLsT0GeAcU2mOzlh0PQGlEx6ggrhwuJi69MTfFWo
|
||||
Sa+QOnPOkGAg781nGbsV5704fjWbj306Ocf6Rfi8/H6KeMD/v/axhjm6PY0M9tg1
|
||||
FFt1+0c+Gx29AU70mPe9wDZM+sDTk+NpYs0XPRJZzb6SlI3I1LV0454f0J3f5Bmq
|
||||
+d8UtyOro4OOnjxEeCn4N6cIrSKpr8tCfZAWVbb++NOt+jcY5lfjmFxLk786Radi
|
||||
Hd+wVsa8GPstkQKCAQEAyju+0TOion3iBMaVqZ/yab2spDMj+G3xDvPdkU1TL1bt
|
||||
5PA8nkY+tUAEqrsZWtGOPMjPE/E/wV3VLzBLsa5nQvE22taXG42Wc7weME0JNsK2
|
||||
6FzGEOuRBXUwqTnMuGu/n0EF03cm+I+p5hBsLgc5Q58hJQfD3ym0GPYcq0qquGDF
|
||||
2wjx6gnruwhro2ULN2Vyd6b3ZnvoMP56dh71xzJ9cegKGCTHWHKWNZqyinzUpPqU
|
||||
75wGz4DgNzHwSGUOlVs/2kea6SzucDYrd+Kpokqzmfm3lsG6YTtraCQVYR2G1KIt
|
||||
MIckeaf+HK99Yttx1WxW9bwgQ7QLEzc7gdqUti/8AwKCAQA4FMg0EPoqRsI7nR+m
|
||||
wJlvhu1WuZhu+IybJl0wa2Go7DrRn8t4ZrPVJ44DBKRQath1AmT8WMHXPQ28vj5T
|
||||
a7FenFDZwjDgBuK8Gfrayfz2w9imooCGMnXGsqtduI5mUwP+diAH00gGF/zRoLUk
|
||||
QrMt41ZkiX78k0NOHkbGv3qaTEkFzOmersnu1JOWCuNMR0bhhfNK3IwrpldziHa2
|
||||
7W9rd360Ninujc5/EO9caJEmG/x+uwhc66jlYUZtVYMQdM611OP8CWt6vq3kt23S
|
||||
x9Zh5IHBC8Mvd8rHE21zJXw6kG0/fpfd+bZy/5lmi9xeck6hH3o1haT/7sLyCqbr
|
||||
MOHBAoIBAQCbOwr4R/tBYQEZi1kb79NCST54d2zX54QOZzAetUzx3HcUsTbGgsLl
|
||||
m3M5ng4TQSE+FSGmfBrlEWJvK1Ie2/EVWFQz3F3231KqGa7OgoNdDk8ZwwShvj/+
|
||||
AXtNmjlDIinfUyjmreIzDwtpthdjqVXSSxZE91XpOXitZFSTQugSSO32eEJA1Eam
|
||||
tQryS8A1UGBx6a6jct7CpMNZYeBke6QAyAzfhXOit6oHEWyUkscir9mcppYvtwvk
|
||||
MifvWeq8yGMV6LrG2x9W8K2jA1AUa+S6fwzl4mRu+A40zOXAOsrg8m9ffYyI+WM7
|
||||
n5TOSgVxvgxt6W6WqV+K6214+lAGHIUDAoIBAFpoDk3M/AaI520H4QNB5H+H9eAT
|
||||
tVm/t/IeomuOHF3A6Px+ghMjSlOGcil6Nq/gDXbJp5ZDHC5kVxvrBpt3ggnSvkPQ
|
||||
i6w8OLAa7ox73ry4zJ37pYk0GhMh6oa0ImwYB6BungOkxZ5iqfDCaROHQnhk+qc2
|
||||
64TY1q2dTbuXC1lM4oz9+0IfO5gSF2C4XHa71H0SCqDmIgh3G1hUay9q+ja6E07J
|
||||
jEUH0DT671YHu/ZWTb9Fo1f3MWalY5JT8fzaOkpq6OsJJP8X0tnuQGQxdxC2Mfpf
|
||||
FCzAWb3eGATF3GQimhxrjdiwDXn14p4XIds+hx6+gsxtK1HHIXb8dobUnk8=
|
||||
-----END RSA PRIVATE KEY-----
|
@ -18,6 +18,9 @@
|
||||
-export([validate_rekey/3]).
|
||||
-export([cancel_rekey/1]).
|
||||
-export([get_state/1]).
|
||||
-export([update_keyring_meta/2]).
|
||||
-export([get_keyring_meta/1]).
|
||||
-export([get_keyring/2]).
|
||||
|
||||
%%
|
||||
%% Internal types
|
||||
@ -35,7 +38,7 @@
|
||||
{error, {invalid_activity, {initialization, kds_keyring_initializer:state()}}} |
|
||||
{error, {invalid_arguments, binary()}}.
|
||||
start_init(Threshold, RootUrl) ->
|
||||
try kds_woody_client:call(keyring_v2, 'StartInit', [Threshold], RootUrl) of
|
||||
try kds_woody_client:call(keyring_management, 'StartInit', [Threshold], RootUrl) of
|
||||
EncryptedShares ->
|
||||
decode_encrypted_shares(EncryptedShares)
|
||||
catch
|
||||
@ -54,7 +57,7 @@ start_init(Threshold, RootUrl) ->
|
||||
{error, verification_failed} |
|
||||
{error, {invalid_arguments, binary()}}.
|
||||
validate_init(ShareholderId, Share, RootUrl) ->
|
||||
try kds_woody_client:call(keyring_v2, 'ValidateInit', [ShareholderId, Share], RootUrl) of
|
||||
try kds_woody_client:call(keyring_management, 'ValidateInit', [ShareholderId, Share], RootUrl) of
|
||||
{success, #'Success'{}} ->
|
||||
ok;
|
||||
{more_keys_needed, More} ->
|
||||
@ -75,7 +78,7 @@ validate_init(ShareholderId, Share, RootUrl) ->
|
||||
{error, {invalid_status, kds_keyring_manager:state()}} |
|
||||
{error, {invalid_activity, {initialization, kds_keyring_initializer:state()}}}.
|
||||
cancel_init(RootUrl) ->
|
||||
try kds_woody_client:call(keyring_v2, 'CancelInit', [], RootUrl) catch
|
||||
try kds_woody_client:call(keyring_management, 'CancelInit', [], RootUrl) catch
|
||||
#'InvalidStatus'{status = Status} ->
|
||||
{error, {invalid_status, Status}};
|
||||
#'InvalidActivity'{activity = Activity} ->
|
||||
@ -87,7 +90,7 @@ cancel_init(RootUrl) ->
|
||||
{error, {invalid_status, kds_keyring_manager:state()}} |
|
||||
{error, {invalid_activity, {unlock, kds_keyring_unlocker:state()}}}.
|
||||
start_unlock(RootUrl) ->
|
||||
try kds_woody_client:call(keyring_v2, 'StartUnlock', [], RootUrl) catch
|
||||
try kds_woody_client:call(keyring_management, 'StartUnlock', [], RootUrl) catch
|
||||
#'InvalidStatus'{status = Status} ->
|
||||
{error, {invalid_status, Status}};
|
||||
#'InvalidActivity'{activity = Activity} ->
|
||||
@ -101,7 +104,7 @@ start_unlock(RootUrl) ->
|
||||
{error, verification_failed} |
|
||||
{error, {operation_aborted, binary()}}.
|
||||
confirm_unlock(ShareholderId, Share, RootUrl) ->
|
||||
try kds_woody_client:call(keyring_v2, 'ConfirmUnlock', [ShareholderId, Share], RootUrl) of
|
||||
try kds_woody_client:call(keyring_management, 'ConfirmUnlock', [ShareholderId, Share], RootUrl) of
|
||||
{success, #'Success'{}} ->
|
||||
ok;
|
||||
{more_keys_needed, More} ->
|
||||
@ -121,7 +124,7 @@ confirm_unlock(ShareholderId, Share, RootUrl) ->
|
||||
ok |
|
||||
{error, {invalid_status, kds_keyring_manager:state()}}.
|
||||
cancel_unlock(RootUrl) ->
|
||||
try kds_woody_client:call(keyring_v2, 'CancelUnlock', [], RootUrl) catch
|
||||
try kds_woody_client:call(keyring_management, 'CancelUnlock', [], RootUrl) catch
|
||||
#'InvalidStatus'{status = Status} ->
|
||||
{error, {invalid_status, Status}}
|
||||
end.
|
||||
@ -130,7 +133,7 @@ cancel_unlock(RootUrl) ->
|
||||
ok |
|
||||
{error, {invalid_status, kds_keyring_manager:state()}}.
|
||||
lock(RootUrl) ->
|
||||
try kds_woody_client:call(keyring_v2, 'Lock', [], RootUrl) catch
|
||||
try kds_woody_client:call(keyring_management, 'Lock', [], RootUrl) catch
|
||||
#'InvalidStatus'{status = Status} ->
|
||||
{error, {invalid_status, Status}}
|
||||
end.
|
||||
@ -140,7 +143,7 @@ lock(RootUrl) ->
|
||||
{error, {invalid_status, kds_keyring_manager:state()}} |
|
||||
{error, {invalid_activity, {rotation, kds_keyring_rotator:state()}}}.
|
||||
start_rotate(RootUrl) ->
|
||||
try kds_woody_client:call(keyring_v2, 'StartRotate', [], RootUrl) catch
|
||||
try kds_woody_client:call(keyring_management, 'StartRotate', [], RootUrl) catch
|
||||
#'InvalidStatus'{status = Status} ->
|
||||
{error, {invalid_status, Status}};
|
||||
#'InvalidActivity'{activity = Activity} ->
|
||||
@ -154,7 +157,7 @@ start_rotate(RootUrl) ->
|
||||
{error, verification_failed} |
|
||||
{error, {operation_aborted, binary()}}.
|
||||
confirm_rotate(ShareholderId, Share, RootUrl) ->
|
||||
try kds_woody_client:call(keyring_v2, 'ConfirmRotate', [ShareholderId, Share], RootUrl) of
|
||||
try kds_woody_client:call(keyring_management, 'ConfirmRotate', [ShareholderId, Share], RootUrl) of
|
||||
{success, #'Success'{}} ->
|
||||
ok;
|
||||
{more_keys_needed, More} ->
|
||||
@ -174,7 +177,7 @@ confirm_rotate(ShareholderId, Share, RootUrl) ->
|
||||
ok |
|
||||
{error, {invalid_status, kds_keyring_manager:state()}}.
|
||||
cancel_rotate(RootUrl) ->
|
||||
try kds_woody_client:call(keyring_v2, 'CancelRotate', [], RootUrl) catch
|
||||
try kds_woody_client:call(keyring_management, 'CancelRotate', [], RootUrl) catch
|
||||
#'InvalidStatus'{status = Status} ->
|
||||
{error, {invalid_status, Status}}
|
||||
end.
|
||||
@ -185,7 +188,7 @@ cancel_rotate(RootUrl) ->
|
||||
{error, {invalid_activity, {rekeying, kds_keyring_rotator:state()}}} |
|
||||
{error, {invalid_arguments, binary()}}.
|
||||
start_rekey(Threshold, RootUrl) ->
|
||||
try kds_woody_client:call(keyring_v2, 'StartRekey', [Threshold], RootUrl) catch
|
||||
try kds_woody_client:call(keyring_management, 'StartRekey', [Threshold], RootUrl) catch
|
||||
#'InvalidStatus'{status = Status} ->
|
||||
{error, {invalid_status, Status}};
|
||||
#'InvalidActivity'{activity = Activity} ->
|
||||
@ -201,7 +204,7 @@ start_rekey(Threshold, RootUrl) ->
|
||||
{error, verification_failed} |
|
||||
{error, {operation_aborted, binary()}}.
|
||||
confirm_rekey(ShareholderId, Share, RootUrl) ->
|
||||
try kds_woody_client:call(keyring_v2, 'ConfirmRekey', [ShareholderId, Share], RootUrl) of
|
||||
try kds_woody_client:call(keyring_management, 'ConfirmRekey', [ShareholderId, Share], RootUrl) of
|
||||
{success, #'Success'{}} ->
|
||||
ok;
|
||||
{more_keys_needed, More} ->
|
||||
@ -222,7 +225,7 @@ confirm_rekey(ShareholderId, Share, RootUrl) ->
|
||||
{error, {invalid_status, kds_keyring_manager:state()}} |
|
||||
{error, {invalid_activity, {rekeying, kds_keyring_rotator:state()}}}.
|
||||
start_rekey_validation(RootUrl) ->
|
||||
try kds_woody_client:call(keyring_v2, 'StartRekeyValidation', [], RootUrl) of
|
||||
try kds_woody_client:call(keyring_management, 'StartRekeyValidation', [], RootUrl) of
|
||||
EncryptedShares ->
|
||||
decode_encrypted_shares(EncryptedShares)
|
||||
catch
|
||||
@ -239,7 +242,7 @@ start_rekey_validation(RootUrl) ->
|
||||
{error, verification_failed} |
|
||||
{error, {operation_aborted, binary()}}.
|
||||
validate_rekey(ShareholderId, Share, RootUrl) ->
|
||||
try kds_woody_client:call(keyring_v2, 'ValidateRekey', [ShareholderId, Share], RootUrl) of
|
||||
try kds_woody_client:call(keyring_management, 'ValidateRekey', [ShareholderId, Share], RootUrl) of
|
||||
{success, #'Success'{}} ->
|
||||
ok;
|
||||
{more_keys_needed, More} ->
|
||||
@ -259,7 +262,7 @@ validate_rekey(ShareholderId, Share, RootUrl) ->
|
||||
ok |
|
||||
{error, {invalid_status, kds_keyring_manager:state()}}.
|
||||
cancel_rekey(RootUrl) ->
|
||||
try kds_woody_client:call(keyring_v2, 'CancelRekey', [], RootUrl)
|
||||
try kds_woody_client:call(keyring_management, 'CancelRekey', [], RootUrl)
|
||||
catch
|
||||
#'InvalidStatus'{status = Status} ->
|
||||
{error, {invalid_status, Status}}
|
||||
@ -267,9 +270,48 @@ cancel_rekey(RootUrl) ->
|
||||
|
||||
-spec get_state(woody:url()) -> kds_keyring_manager:status().
|
||||
get_state(RootUrl) ->
|
||||
State = kds_woody_client:call(keyring_v2, 'GetState', [], RootUrl),
|
||||
State = kds_woody_client:call(keyring_management, 'GetState', [], RootUrl),
|
||||
decode_state(State).
|
||||
|
||||
-spec update_keyring_meta(kds_keyring_meta:keyring_meta(), woody:url()) ->
|
||||
ok |
|
||||
{error, {invalid_keyring_meta, binary()}} |
|
||||
{error, {invalid_status, kds_keyring_manager:state()}}.
|
||||
update_keyring_meta(KeyringMeta, RootUrl) ->
|
||||
try
|
||||
EncodedMeta = kds_keyring_meta:encode_keyring_meta_diff(KeyringMeta),
|
||||
kds_woody_client:call(keyring_management, 'UpdateKeyringMeta', [EncodedMeta], RootUrl)
|
||||
catch
|
||||
#'InvalidKeyringMeta'{reason = Reason} ->
|
||||
{error, {invalid_keyring_meta, Reason}};
|
||||
#'InvalidStatus'{status = Status} ->
|
||||
{error, {invalid_status, Status}}
|
||||
end.
|
||||
|
||||
-spec get_keyring_meta(woody:url()) -> kds_keyring_meta:keyring_meta().
|
||||
get_keyring_meta(RootUrl) ->
|
||||
KeyringMeta = kds_woody_client:call(keyring_management, 'GetKeyringMeta', [], RootUrl),
|
||||
kds_keyring_meta:decode_keyring_meta(KeyringMeta).
|
||||
|
||||
-spec get_keyring(woody:url(), term()) -> kds_keyring:keyring().
|
||||
get_keyring(RootUrl, SSLOptions) ->
|
||||
ExtraOpts = #{
|
||||
transport_opts => #{
|
||||
ssl_options => [
|
||||
{server_name_indication, "Test Server"},
|
||||
{verify, verify_peer} |
|
||||
SSLOptions
|
||||
]
|
||||
}
|
||||
},
|
||||
try kds_woody_client:call(keyring_storage, 'GetKeyring', [], RootUrl, ExtraOpts) of
|
||||
Keyring ->
|
||||
decode_keyring(Keyring)
|
||||
catch
|
||||
#'InvalidStatus'{status = Status} ->
|
||||
{error, {invalid_status, Status}}
|
||||
end.
|
||||
|
||||
decode_state(#'KeyringState'{
|
||||
status = Status,
|
||||
activities = #'ActivitiesState'{
|
||||
@ -341,4 +383,38 @@ decode_encrypted_share(#'EncryptedMasterKeyShare' {
|
||||
id => Id,
|
||||
owner => Owner,
|
||||
encrypted_share => EncryptedShare
|
||||
}.
|
||||
}.
|
||||
|
||||
decode_keyring(#'Keyring'{
|
||||
version = Version,
|
||||
current_key_id = CurrentKeyId,
|
||||
keys = Keys
|
||||
}) ->
|
||||
#{
|
||||
data => #{
|
||||
keys => decode_keys(Keys)
|
||||
},
|
||||
meta => #{
|
||||
current_key_id => CurrentKeyId,
|
||||
version => Version,
|
||||
keys => decode_keys_meta(Keys)
|
||||
}
|
||||
}.
|
||||
|
||||
decode_keys(Keys) ->
|
||||
maps:fold(
|
||||
fun (K, #'Key'{data = KeyData}, Acc) ->
|
||||
Acc#{K => KeyData}
|
||||
end,
|
||||
#{},
|
||||
Keys
|
||||
).
|
||||
|
||||
decode_keys_meta(Keys) ->
|
||||
maps:fold(
|
||||
fun (K, #'Key'{meta = #'KeyMeta'{retired = Retired}}, Acc) ->
|
||||
Acc#{K => #{retired => Retired}}
|
||||
end,
|
||||
#{},
|
||||
Keys
|
||||
).
|
||||
|
196
apps/kds/test/kds_keyring_meta_api_tests_SUITE.erl
Normal file
196
apps/kds/test/kds_keyring_meta_api_tests_SUITE.erl
Normal file
@ -0,0 +1,196 @@
|
||||
-module(kds_keyring_meta_api_tests_SUITE).
|
||||
|
||||
-include_lib("common_test/include/ct.hrl").
|
||||
-include_lib("eunit/include/eunit.hrl").
|
||||
-include_lib("shamir/include/shamir.hrl").
|
||||
|
||||
-export([all/0]).
|
||||
-export([groups/0]).
|
||||
-export([init_per_group/2]).
|
||||
-export([end_per_group/2]).
|
||||
|
||||
-export([init_check_meta/1]).
|
||||
-export([rotate_check_meta/1]).
|
||||
-export([update_meta/1]).
|
||||
-export([rotate_collision_check/1]).
|
||||
|
||||
-type config() :: [tuple()].
|
||||
|
||||
-spec test() -> _.
|
||||
|
||||
-spec all() -> [{group, atom()}].
|
||||
|
||||
all() ->
|
||||
[
|
||||
{group, basic_lifecycle}
|
||||
].
|
||||
|
||||
-spec groups() -> [{atom(), list(), [atom()]}].
|
||||
|
||||
groups() ->
|
||||
[
|
||||
{basic_lifecycle, [sequence], [
|
||||
init_check_meta,
|
||||
rotate_check_meta,
|
||||
update_meta,
|
||||
rotate_collision_check
|
||||
]}
|
||||
].
|
||||
|
||||
%%
|
||||
%% starting/stopping
|
||||
%%
|
||||
|
||||
-spec init_per_group(atom(), config()) -> config().
|
||||
|
||||
init_per_group(_, C) ->
|
||||
C1 = kds_ct_utils:start_stash(C),
|
||||
C2 = kds_ct_utils:start_clear(C1),
|
||||
{ok, EncPrivateKey1} = file:read_file(filename:join(config(data_dir, C2), "enc.1.priv.json")),
|
||||
{ok, EncPrivateKey2} = file:read_file(filename:join(config(data_dir, C2), "enc.2.priv.json")),
|
||||
{ok, EncPrivateKey3} = file:read_file(filename:join(config(data_dir, C2), "enc.3.priv.json")),
|
||||
EncPrivateKeys = #{<<"1">> => EncPrivateKey1, <<"2">> => EncPrivateKey2, <<"3">> => EncPrivateKey3},
|
||||
{ok, SigPrivateKey1} = file:read_file(filename:join(config(data_dir, C2), "sig.1.priv.json")),
|
||||
{ok, SigPrivateKey2} = file:read_file(filename:join(config(data_dir, C2), "sig.2.priv.json")),
|
||||
{ok, SigPrivateKey3} = file:read_file(filename:join(config(data_dir, C2), "sig.3.priv.json")),
|
||||
SigPrivateKeys = #{<<"1">> => SigPrivateKey1, <<"2">> => SigPrivateKey2, <<"3">> => SigPrivateKey3},
|
||||
[
|
||||
{enc_private_keys, EncPrivateKeys},
|
||||
{sig_private_keys, SigPrivateKeys}
|
||||
] ++ C2.
|
||||
|
||||
-spec end_per_group(atom(), config()) -> _.
|
||||
|
||||
end_per_group(_, C) ->
|
||||
kds_ct_utils:stop_clear(C).
|
||||
|
||||
-spec init_check_meta(config()) -> _.
|
||||
|
||||
init_check_meta(C) ->
|
||||
_ = ?assertMatch(
|
||||
#{keys := #{}, current_key_id := 0},
|
||||
kds_keyring_client:get_keyring_meta(root_url(C))
|
||||
),
|
||||
_ = ?assertMatch(
|
||||
{error, {invalid_status, not_initialized}},
|
||||
kds_keyring_client:update_keyring_meta(
|
||||
#{keys => #{0 => #{retired => true}}},
|
||||
root_url(C))
|
||||
),
|
||||
_ = ?assertMatch(
|
||||
#{keys := #{}, current_key_id := 0},
|
||||
kds_keyring_client:get_keyring_meta(root_url(C))
|
||||
),
|
||||
_ = kds_ct_keyring:init(C),
|
||||
_ = ?assertMatch(
|
||||
#{keys := #{0 := #{retired := false}}, current_key_id := 0},
|
||||
kds_keyring_client:get_keyring_meta(root_url(C))
|
||||
).
|
||||
|
||||
-spec rotate_check_meta(config()) -> _.
|
||||
|
||||
rotate_check_meta(C) ->
|
||||
_ = ?assertMatch(
|
||||
#{keys := #{0 := #{retired := false}}},
|
||||
kds_keyring_client:get_keyring_meta(root_url(C))
|
||||
),
|
||||
_ = kds_ct_keyring:rotate(C),
|
||||
_ = ?assertMatch(
|
||||
#{keys := #{
|
||||
0 := #{retired := false},
|
||||
1 := #{retired := false}
|
||||
}},
|
||||
kds_keyring_client:get_keyring_meta(root_url(C))
|
||||
).
|
||||
|
||||
-spec update_meta(config()) -> _.
|
||||
|
||||
update_meta(C) ->
|
||||
_ = ?assertMatch(
|
||||
#{
|
||||
current_key_id := 0,
|
||||
keys := #{
|
||||
0 := #{retired := false},
|
||||
1 := #{retired := false}
|
||||
}
|
||||
},
|
||||
kds_keyring_client:get_keyring_meta(root_url(C))
|
||||
),
|
||||
ok = kds_keyring_client:update_keyring_meta(
|
||||
#{keys => #{0 => #{retired => true}}},
|
||||
root_url(C)),
|
||||
ok = kds_keyring_client:update_keyring_meta(
|
||||
#{keys => #{0 => #{retired => true}}},
|
||||
root_url(C)),
|
||||
_ = ?assertMatch(
|
||||
#{
|
||||
current_key_id := 0,
|
||||
keys := #{
|
||||
0 := #{retired := true},
|
||||
1 := #{retired := false}
|
||||
}
|
||||
},
|
||||
kds_keyring_client:get_keyring_meta(root_url(C))
|
||||
),
|
||||
ok = kds_keyring_client:update_keyring_meta(
|
||||
#{current_key_id => 1},
|
||||
root_url(C)),
|
||||
_ = ?assertMatch(
|
||||
#{
|
||||
current_key_id := 1,
|
||||
keys := #{
|
||||
0 := #{retired := true},
|
||||
1 := #{retired := false}
|
||||
}
|
||||
},
|
||||
kds_keyring_client:get_keyring_meta(root_url(C))
|
||||
)
|
||||
.
|
||||
|
||||
-spec rotate_collision_check(config()) -> _.
|
||||
|
||||
rotate_collision_check(C) ->
|
||||
[{Id1, MasterKey1}, {Id2, MasterKey2}, _MasterKey3] = kds_ct_utils:lookup(master_keys, C),
|
||||
ok = kds_keyring_client:start_rotate(root_url(C)),
|
||||
{more_keys_needed, 1} = kds_keyring_client:confirm_rotate(Id1, MasterKey1, root_url(C)),
|
||||
_ = ?assertMatch(
|
||||
#{
|
||||
current_key_id := 1,
|
||||
keys := #{
|
||||
0 := #{retired := true},
|
||||
1 := #{retired := false}
|
||||
}},
|
||||
kds_keyring_client:get_keyring_meta(root_url(C))
|
||||
),
|
||||
ok = kds_keyring_client:update_keyring_meta(
|
||||
#{keys => #{0 => #{retired => false}}},
|
||||
root_url(C)),
|
||||
ok = kds_keyring_client:confirm_rotate(Id2, MasterKey2, root_url(C)),
|
||||
_ = ?assertMatch(
|
||||
#{
|
||||
current_key_id := 1,
|
||||
keys := #{
|
||||
0 := #{retired := false},
|
||||
1 := #{retired := false},
|
||||
2 := #{retired := false}
|
||||
}},
|
||||
kds_keyring_client:get_keyring_meta(root_url(C))
|
||||
).
|
||||
|
||||
%%
|
||||
%% internal
|
||||
%%
|
||||
|
||||
config(Key, Config) ->
|
||||
config(Key, Config, undefined).
|
||||
|
||||
config(Key, Config, Default) ->
|
||||
case lists:keysearch(Key, 1, Config) of
|
||||
{value, {Key, Val}} ->
|
||||
Val;
|
||||
_ ->
|
||||
Default
|
||||
end.
|
||||
|
||||
root_url(C) ->
|
||||
config(management_root_url, C).
|
1
apps/kds/test/kds_keyring_meta_api_tests_SUITE_data
Symbolic link
1
apps/kds/test/kds_keyring_meta_api_tests_SUITE_data
Symbolic link
@ -0,0 +1 @@
|
||||
kds_keyring_api_tests_SUITE_data/
|
202
apps/kds/test/kds_keyring_storage_api_tests_SUITE.erl
Normal file
202
apps/kds/test/kds_keyring_storage_api_tests_SUITE.erl
Normal file
@ -0,0 +1,202 @@
|
||||
-module(kds_keyring_storage_api_tests_SUITE).
|
||||
|
||||
-include_lib("common_test/include/ct.hrl").
|
||||
-include_lib("eunit/include/eunit.hrl").
|
||||
-include_lib("shamir/include/shamir.hrl").
|
||||
|
||||
-export([all/0]).
|
||||
-export([groups/0]).
|
||||
-export([init_per_group/2]).
|
||||
-export([end_per_group/2]).
|
||||
|
||||
-export([init_check_keyring/1]).
|
||||
-export([locked_unlocked_check_keyring/1]).
|
||||
-export([rotation_version_check/1]).
|
||||
-export([update_meta_version_check/1]).
|
||||
|
||||
-type config() :: [{tuple()}].
|
||||
|
||||
-spec test() -> _.
|
||||
|
||||
-spec all() -> [{group, atom()}].
|
||||
|
||||
all() ->
|
||||
[
|
||||
{group, basic_lifecycle}
|
||||
].
|
||||
|
||||
-spec groups() -> [{atom(), list(), [atom()]}].
|
||||
|
||||
groups() ->
|
||||
[
|
||||
{basic_lifecycle, [sequence], [
|
||||
init_check_keyring,
|
||||
locked_unlocked_check_keyring,
|
||||
rotation_version_check,
|
||||
update_meta_version_check
|
||||
]}
|
||||
].
|
||||
|
||||
%%
|
||||
%% starting/stopping
|
||||
%%
|
||||
|
||||
-spec init_per_group(atom(), config()) -> config().
|
||||
|
||||
init_per_group(_, C) ->
|
||||
C1 = kds_ct_utils:start_stash(C),
|
||||
C2 = kds_ct_utils:start_clear(C1),
|
||||
{ok, EncPrivateKey1} = file:read_file(filename:join(config(data_dir, C2), "enc.1.priv.json")),
|
||||
{ok, EncPrivateKey2} = file:read_file(filename:join(config(data_dir, C2), "enc.2.priv.json")),
|
||||
{ok, EncPrivateKey3} = file:read_file(filename:join(config(data_dir, C2), "enc.3.priv.json")),
|
||||
EncPrivateKeys = #{<<"1">> => EncPrivateKey1, <<"2">> => EncPrivateKey2, <<"3">> => EncPrivateKey3},
|
||||
{ok, SigPrivateKey1} = file:read_file(filename:join(config(data_dir, C2), "sig.1.priv.json")),
|
||||
{ok, SigPrivateKey2} = file:read_file(filename:join(config(data_dir, C2), "sig.2.priv.json")),
|
||||
{ok, SigPrivateKey3} = file:read_file(filename:join(config(data_dir, C2), "sig.3.priv.json")),
|
||||
SigPrivateKeys = #{<<"1">> => SigPrivateKey1, <<"2">> => SigPrivateKey2, <<"3">> => SigPrivateKey3},
|
||||
[
|
||||
{enc_private_keys, EncPrivateKeys},
|
||||
{sig_private_keys, SigPrivateKeys}
|
||||
] ++ C2.
|
||||
|
||||
-spec end_per_group(atom(), config()) -> _.
|
||||
|
||||
end_per_group(_, C) ->
|
||||
kds_ct_utils:stop_clear(C).
|
||||
|
||||
-spec init_check_keyring(config()) -> _.
|
||||
|
||||
init_check_keyring(C) ->
|
||||
_ = ?assertEqual(
|
||||
{error, {invalid_status, not_initialized}},
|
||||
get_keyring(C)
|
||||
),
|
||||
_ = kds_ct_keyring:init(C),
|
||||
_ = ?assertMatch(
|
||||
#{
|
||||
meta := #{current_key_id := 0, version := 1, keys := #{0 := #{retired := false}}},
|
||||
data := #{keys := #{0 := _Key0}}
|
||||
},
|
||||
get_keyring(C)
|
||||
).
|
||||
|
||||
-spec locked_unlocked_check_keyring(config()) -> _.
|
||||
|
||||
locked_unlocked_check_keyring(C) ->
|
||||
_ = ?assertMatch(
|
||||
#{
|
||||
meta := #{current_key_id := 0, version := 1, keys := #{0 := #{retired := false}}},
|
||||
data := #{keys := #{0 := _Key0}}
|
||||
},
|
||||
get_keyring(C)
|
||||
),
|
||||
_ = kds_ct_keyring:lock(C),
|
||||
_ = ?assertEqual(
|
||||
{error, {invalid_status, locked}},
|
||||
get_keyring(C)
|
||||
),
|
||||
_ = kds_ct_keyring:unlock(C),
|
||||
_ = ?assertMatch(
|
||||
#{
|
||||
meta := #{current_key_id := 0, version := 1, keys := #{0 := #{retired := false}}},
|
||||
data := #{keys := #{0 := _Key0}}
|
||||
},
|
||||
get_keyring(C)
|
||||
).
|
||||
|
||||
-spec rotation_version_check(config()) -> _.
|
||||
|
||||
rotation_version_check(C) ->
|
||||
_ = ?assertMatch(
|
||||
#{
|
||||
meta := #{current_key_id := 0, version := 1, keys := #{0 := #{retired := false}}},
|
||||
data := #{keys := #{0 := _Key0}}
|
||||
},
|
||||
get_keyring(C)
|
||||
),
|
||||
_ = kds_ct_keyring:rotate(C),
|
||||
_ = ?assertMatch(
|
||||
#{
|
||||
meta := #{
|
||||
current_key_id := 0,
|
||||
version := 2,
|
||||
keys := #{0 := #{retired := false}, 1 := #{retired := false}}
|
||||
},
|
||||
data := #{keys := #{0 := _Key0, 1 := _Key1}}
|
||||
},
|
||||
get_keyring(C)
|
||||
).
|
||||
|
||||
-spec update_meta_version_check(config()) -> _.
|
||||
|
||||
update_meta_version_check(C) ->
|
||||
_ = ?assertMatch(
|
||||
#{
|
||||
meta := #{
|
||||
current_key_id := 0,
|
||||
version := 2,
|
||||
keys := #{0 := #{retired := false}, 1 := #{retired := false}}
|
||||
},
|
||||
data := #{keys := #{0 := _Key0, 1 := _Key1}}
|
||||
},
|
||||
get_keyring(C)
|
||||
),
|
||||
ok = kds_keyring_client:update_keyring_meta(
|
||||
#{keys => #{0 => #{retired => true}}},
|
||||
management_root_url(C)),
|
||||
_ = ?assertMatch(
|
||||
#{
|
||||
meta := #{
|
||||
current_key_id := 0,
|
||||
version := 3,
|
||||
keys := #{0 := #{retired := true}, 1 := #{retired := false}}
|
||||
},
|
||||
data := #{keys := #{0 := _Key0, 1 := _Key1}}
|
||||
},
|
||||
get_keyring(C)
|
||||
),
|
||||
ok = kds_keyring_client:update_keyring_meta(
|
||||
#{current_key_id => 1},
|
||||
management_root_url(C)),
|
||||
_ = ?assertMatch(
|
||||
#{
|
||||
meta := #{
|
||||
current_key_id := 1,
|
||||
version := 4,
|
||||
keys := #{0 := #{retired := true}, 1 := #{retired := false}}
|
||||
},
|
||||
data := #{keys := #{0 := _Key0, 1 := _Key1}}
|
||||
},
|
||||
get_keyring(C)
|
||||
).
|
||||
|
||||
%%
|
||||
%% internal
|
||||
%%
|
||||
|
||||
get_keyring(C) ->
|
||||
SSLOpts = [{cacertfile, cacertfile(C)}, {certfile, clientcertfile(C)}],
|
||||
kds_keyring_client:get_keyring(storage_root_url(C), SSLOpts).
|
||||
|
||||
config(Key, Config) ->
|
||||
config(Key, Config, undefined).
|
||||
|
||||
config(Key, Config, Default) ->
|
||||
case lists:keysearch(Key, 1, Config) of
|
||||
{value, {Key, Val}} ->
|
||||
Val;
|
||||
_ ->
|
||||
Default
|
||||
end.
|
||||
|
||||
storage_root_url(C) ->
|
||||
config(storage_root_url, C).
|
||||
|
||||
management_root_url(C) ->
|
||||
config(management_root_url, C).
|
||||
|
||||
cacertfile(C) ->
|
||||
config(cacertfile, C).
|
||||
|
||||
clientcertfile(C) ->
|
||||
config(clientcertfile, C).
|
1
apps/kds/test/kds_keyring_storage_api_tests_SUITE_data
Symbolic link
1
apps/kds/test/kds_keyring_storage_api_tests_SUITE_data
Symbolic link
@ -0,0 +1 @@
|
||||
kds_keyring_api_tests_SUITE_data/
|
@ -13,13 +13,17 @@
|
||||
-export([update/1]).
|
||||
-export([delete/1]).
|
||||
|
||||
-type config() :: term().
|
||||
-export([create_old_format/1]).
|
||||
-export([read_old_format/1]).
|
||||
|
||||
-type config() :: [tuple()].
|
||||
|
||||
-spec all() -> [{group, atom()}].
|
||||
|
||||
all() ->
|
||||
[
|
||||
{group, file_storage_lifecycle}
|
||||
{group, file_storage_lifecycle},
|
||||
{group, backward_compatibility}
|
||||
].
|
||||
|
||||
-spec groups() -> [{atom(), list(), [atom()]}].
|
||||
@ -32,6 +36,13 @@ groups() ->
|
||||
read,
|
||||
update,
|
||||
delete
|
||||
]},
|
||||
{backward_compatibility, [sequence], [
|
||||
create_old_format,
|
||||
already_exists,
|
||||
read_old_format,
|
||||
update,
|
||||
delete
|
||||
]}
|
||||
].
|
||||
|
||||
@ -41,38 +52,36 @@ groups() ->
|
||||
|
||||
-spec init_per_group(atom(), config()) -> config().
|
||||
|
||||
init_per_group(file_storage_lifecycle, C) ->
|
||||
kds_ct_utils:start_clear(C);
|
||||
|
||||
init_per_group(_, C) ->
|
||||
C.
|
||||
C1 = kds_ct_utils:start_stash(C),
|
||||
kds_ct_utils:start_clear(C1).
|
||||
|
||||
-spec end_per_group(atom(), config()) -> config().
|
||||
|
||||
end_per_group(_, _C) ->
|
||||
ok.
|
||||
end_per_group(_, C) ->
|
||||
kds_ct_utils:stop_clear(C).
|
||||
|
||||
-spec create(config()) -> _.
|
||||
|
||||
create(_C) ->
|
||||
Keyring = <<"initial">>,
|
||||
Keyring = #{data => <<"initial">>, meta => #{current_key_id => 0, version => 1, keys => #{}}},
|
||||
ok = kds_keyring_storage:create(Keyring).
|
||||
|
||||
-spec already_exists(config()) -> _.
|
||||
|
||||
already_exists(_C) ->
|
||||
Keyring = <<"bla">>,
|
||||
Keyring = #{data => <<"bla">>, meta => #{current_key_id => 0, version => 1, keys => #{}}},
|
||||
already_exists = (catch kds_keyring_storage:create(Keyring)).
|
||||
|
||||
-spec read(config()) -> _.
|
||||
|
||||
read(_C) ->
|
||||
<<"initial">> = kds_keyring_storage:read().
|
||||
#{data := <<"initial">>, meta := #{current_key_id := 0, version := 1, keys := #{}}} = kds_keyring_storage:read().
|
||||
|
||||
-spec update(config()) -> _.
|
||||
|
||||
update(_C) ->
|
||||
NewKeyring = <<"updated keyring">>,
|
||||
NewKeyring = #{data => <<"updated keyring">>, meta => #{current_key_id => 0, version => 2, keys => #{}}},
|
||||
kds_keyring_storage:update(NewKeyring),
|
||||
NewKeyring = kds_keyring_storage:read().
|
||||
|
||||
@ -80,3 +89,26 @@ update(_C) ->
|
||||
|
||||
delete(_C) ->
|
||||
ok = kds_keyring_storage:delete().
|
||||
|
||||
-spec create_old_format(config()) -> _.
|
||||
|
||||
create_old_format(C) ->
|
||||
KeyringStorageOpts = application:get_env(kds, keyring_storage_opts, #{}),
|
||||
KeyringPath = maps:get(keyring_path, KeyringStorageOpts, filename:join(config(priv_dir, C), "keyring")),
|
||||
ok = file:write_file(KeyringPath, <<"initial">>).
|
||||
|
||||
-spec read_old_format(config()) -> _.
|
||||
|
||||
read_old_format(_C) ->
|
||||
#{data := <<"initial">>, meta := undefined} = kds_keyring_storage:read().
|
||||
|
||||
config(Key, Config) ->
|
||||
config(Key, Config, undefined).
|
||||
|
||||
config(Key, Config, Default) ->
|
||||
case lists:keysearch(Key, 1, Config) of
|
||||
{value, {Key, Val}} ->
|
||||
Val;
|
||||
_ ->
|
||||
Default
|
||||
end.
|
||||
|
1
apps/kds/test/kds_keyring_storage_tests_SUITE_data
Symbolic link
1
apps/kds/test/kds_keyring_storage_tests_SUITE_data
Symbolic link
@ -0,0 +1 @@
|
||||
kds_keyring_api_tests_SUITE_data/
|
@ -1,8 +1,18 @@
|
||||
[
|
||||
{kds, [
|
||||
{ip, "::"},
|
||||
{port, 8022},
|
||||
{transport_opts, #{}},
|
||||
{management_port, 8022},
|
||||
{storage_port, 8023},
|
||||
{management_transport_opts, #{}},
|
||||
{storage_transport_opts, #{
|
||||
transport => ranch_ssl,
|
||||
socket_opts => [
|
||||
{cacertfile, "/var/lib/kds/ca.crt"},
|
||||
{certfile, "/var/lib/kds/server.pem"},
|
||||
{verify, verify_peer},
|
||||
{fail_if_no_peer_cert, true}
|
||||
]
|
||||
}},
|
||||
{protocol_opts, #{
|
||||
request_timeout => 60000
|
||||
}},
|
||||
|
@ -145,10 +145,10 @@ $ woorl -s cds_proto/proto/keyring.thrift \
|
||||
Keyring StartUnlock
|
||||
```
|
||||
|
||||
### Валидация
|
||||
### Подтверждение
|
||||
|
||||
`Threshold` владельцев фрагментов ключа расшифровывают свою часть, подписывают и отдают
|
||||
на валидацию:
|
||||
на подтверждение:
|
||||
|
||||
```bash
|
||||
$ echo "<insert EncryptedMasterKeyShare here>" | \
|
||||
@ -156,7 +156,7 @@ $ echo "<insert EncryptedMasterKeyShare here>" | \
|
||||
step crypto jws sign - --key ec.json | \
|
||||
woorl -s cds_proto/proto/keyring.thrift \
|
||||
'http://kds:8022/v2/keyring' \
|
||||
Keyring ValidateUnlock '"<insert id, ex. ndiezel>"' '"'"$(cat -)"'"'
|
||||
Keyring ConfirmUnlock '"<insert id, ex. ndiezel>"' '"'"$(cat -)"'"'
|
||||
```
|
||||
|
||||
`EncodedMasterKeyShare` - полученный зашифрованный фрагмент мастер-ключа
|
||||
@ -189,10 +189,10 @@ $ woorl -s cds_proto/proto/keyring.thrift \
|
||||
Keyring StartRotate
|
||||
```
|
||||
|
||||
### Валидация
|
||||
### Подтверждение
|
||||
|
||||
`Threshold` владельцев фрагментов ключа расшифровывают свою часть, подписывают и отдают
|
||||
на валидацию:
|
||||
на подтверждение:
|
||||
|
||||
```bash
|
||||
$ echo "<insert EncryptedMasterKeyShare here>" | \
|
||||
@ -200,7 +200,7 @@ $ echo "<insert EncryptedMasterKeyShare here>" | \
|
||||
step crypto jws sign - --key ec.json | \
|
||||
woorl -s cds_proto/proto/kds.thrift \
|
||||
'http://kds:8022/v2/keyring' \
|
||||
Keyring ValidateRotate '"<insert id, ex. ndiezel>"' '"'"$(cat -)"'"'
|
||||
Keyring ConfirmRotate '"<insert id, ex. ndiezel>"' '"'"$(cat -)"'"'
|
||||
```
|
||||
|
||||
`EncodedMasterKeyShare` - полученный зашифрованный фрагмент мастер-ключа
|
||||
|
16
rebar.config
16
rebar.config
@ -23,14 +23,14 @@
|
||||
{jose, "1.9.0"},
|
||||
{recon , "2.3.2"},
|
||||
{libdecaf, "1.0.0"},
|
||||
{shamir , {git, "git@github.com:rbkmoney/shamir.git" , {branch, master}}} ,
|
||||
{woody , {git, "git@github.com:rbkmoney/woody_erlang.git" , {branch, master}}} ,
|
||||
{logger_logstash_formatter, {git, "git@github.com:rbkmoney/logger_logstash_formatter.git", {branch, master}}} ,
|
||||
{genlib , {git, "git@github.com:rbkmoney/genlib.git" , {branch, master}}} ,
|
||||
{how_are_you , {git, "https://github.com/rbkmoney/how_are_you.git" , {branch, master}}} ,
|
||||
{erl_health , {git, "https://github.com/rbkmoney/erlang-health.git" , {branch, master}}} ,
|
||||
{cds_proto , {git, "git@github.com:rbkmoney/cds-proto.git" , {branch, master}}} ,
|
||||
{msgpack , {git, "https://github.com/rbkmoney/msgpack-erlang" , {branch, master}}} ,
|
||||
{shamir , {git, "git@github.com:rbkmoney/shamir.git" , {branch, master}}},
|
||||
{woody , {git, "git@github.com:rbkmoney/woody_erlang.git" , {branch, master}}},
|
||||
{logger_logstash_formatter, {git, "git@github.com:rbkmoney/logger_logstash_formatter.git", {branch, master}}},
|
||||
{genlib , {git, "git@github.com:rbkmoney/genlib.git" , {branch, master}}},
|
||||
{how_are_you , {git, "https://github.com/rbkmoney/how_are_you.git" , {branch, master}}},
|
||||
{erl_health , {git, "https://github.com/rbkmoney/erlang-health.git" , {branch, master}}},
|
||||
{cds_proto , {git, "git@github.com:rbkmoney/cds-proto.git" , {branch, master}}},
|
||||
{msgpack , {git, "https://github.com/rbkmoney/msgpack-erlang" , {branch, master}}},
|
||||
{scoper , {git, "git@github.com:rbkmoney/scoper.git" , {branch, master}}}
|
||||
]}.
|
||||
|
||||
|
@ -4,7 +4,7 @@
|
||||
{<<"cache">>,{pkg,<<"cache">>,<<"2.2.0">>},1},
|
||||
{<<"cds_proto">>,
|
||||
{git,"git@github.com:rbkmoney/cds-proto.git",
|
||||
{ref,"dc2dac8e82d6a941b7d9b8700b71534d9ff9b211"}},
|
||||
{ref,"a8828869fcc3acbf382b8d4914665f5ef3c19a57"}},
|
||||
0},
|
||||
{<<"certifi">>,{pkg,<<"certifi">>,<<"2.5.1">>},2},
|
||||
{<<"cg_mon">>,
|
||||
|
Loading…
Reference in New Issue
Block a user