CCF
Loading...
Searching...
No Matches
recovery.h
Go to the documentation of this file.
1// Copyright (c) Microsoft Corporation. All rights reserved.
2// Licensed under the Apache 2.0 License.
3#pragma once
4
9
10namespace ccf::gov::endpoints
11{
14 ShareManager& share_manager,
15 ccf::AbstractNodeContext& node_context)
16 {
17 auto get_encrypted_share_for_member =
18 [&](auto& ctx, ApiVersion api_version) {
19 switch (api_version)
20 {
22 case ApiVersion::v1:
23 default:
24 {
25 ccf::MemberId member_id;
26 if (!detail::try_parse_member_id(ctx.rpc_ctx, member_id))
27 {
28 return;
29 }
30
31 auto encrypted_share =
32 ShareManager::get_encrypted_share(ctx.tx, member_id);
33
34 if (!encrypted_share.has_value())
35 {
36 detail::set_gov_error(
37 ctx.rpc_ctx,
38 HTTP_STATUS_NOT_FOUND,
39 ccf::errors::ResourceNotFound,
40 fmt::format(
41 "Recovery share not found for member {}.", member_id));
42 return;
43 }
44
45 auto response_body = nlohmann::json::object();
46 response_body["memberId"] = member_id;
47 response_body["encryptedShare"] =
48 ccf::crypto::b64_from_raw(encrypted_share.value());
49
50 ctx.rpc_ctx->set_response_json(response_body, HTTP_STATUS_OK);
51 return;
52 }
53 }
54 };
55 registry
57 "/recovery/encrypted-shares/{memberId}",
58 HTTP_GET,
59 api_version_adapter(get_encrypted_share_for_member),
60 ccf::no_auth_required)
62 .install();
63
64 auto submit_recovery_share = [&](auto& ctx, ApiVersion api_version) {
65 switch (api_version)
66 {
68 case ApiVersion::v1:
69 default:
70 {
71 if (
74 {
75 detail::set_gov_error(
76 ctx.rpc_ctx,
77 HTTP_STATUS_FORBIDDEN,
78 errors::ServiceNotWaitingForRecoveryShares,
79 "Service is not waiting for recovery shares.");
80 return;
81 }
82
83 auto node_operation =
85 if (node_operation == nullptr)
86 {
87 detail::set_gov_error(
88 ctx.rpc_ctx,
89 HTTP_STATUS_INTERNAL_SERVER_ERROR,
90 ccf::errors::InternalError,
91 "Could not access NodeOperation subsystem.");
92 return;
93 }
94
95 if (node_operation->is_reading_private_ledger())
96 {
97 detail::set_gov_error(
98 ctx.rpc_ctx,
99 HTTP_STATUS_FORBIDDEN,
100 errors::NodeAlreadyRecovering,
101 "Node is already recovering private ledger.");
102 return;
103 }
104
105 ccf::MemberId member_id;
106 if (!detail::try_parse_member_id(ctx.rpc_ctx, member_id))
107 {
108 return;
109 }
110
111 const auto& cose_ident =
112 ctx.template get_caller<ccf::MemberCOSESign1AuthnIdentity>();
113
114 auto params = nlohmann::json::parse(cose_ident.content);
115 if (cose_ident.member_id != member_id)
116 {
117 detail::set_gov_error(
118 ctx.rpc_ctx,
119 HTTP_STATUS_BAD_REQUEST,
120 ccf::errors::InvalidAuthenticationInfo,
121 fmt::format(
122 "Member ID from path parameter ({}) does not match "
123 "member ID from body signature ({}).",
124 member_id,
125 cose_ident.member_id));
126 return;
127 }
128
129 auto raw_recovery_share = ccf::crypto::raw_from_b64(
130 params["share"].template get<std::string>());
131
132 size_t submitted_shares_count = 0;
133 try
134 {
135 submitted_shares_count = share_manager.submit_recovery_share(
136 ctx.tx, member_id, raw_recovery_share);
137
138 OPENSSL_cleanse(
139 raw_recovery_share.data(), raw_recovery_share.size());
140 }
141 catch (const std::exception& e)
142 {
143 OPENSSL_cleanse(
144 raw_recovery_share.data(), raw_recovery_share.size());
145
146 constexpr auto error_msg = "Error submitting recovery shares.";
147 GOV_FAIL_FMT(error_msg);
148 GOV_DEBUG_FMT("Error: {}", e.what());
149 detail::set_gov_error(
150 ctx.rpc_ctx,
151 HTTP_STATUS_INTERNAL_SERVER_ERROR,
152 errors::InternalError,
153 error_msg);
154 return;
155 }
156
157 const auto threshold =
159
160 // Same format of message, whether this is sufficient to trigger
161 // recovery or not
162 std::string message = fmt::format(
163 "{}/{} recovery shares successfully submitted",
164 submitted_shares_count,
165 threshold);
166
167 if (submitted_shares_count >= threshold)
168 {
169 message += "\nEnd of recovery procedure initiated";
170 GOV_INFO_FMT("{} - initiating recovery", message);
171
172 // Initiate recovery
173 try
174 {
175 node_operation->initiate_private_recovery(ctx.tx);
176 }
177 catch (const std::exception& e)
178 {
179 // Clear the submitted shares if combination fails so that members
180 // can start over.
181 constexpr auto error_msg = "Failed to initiate private recovery.";
182 GOV_FAIL_FMT(error_msg);
183 GOV_DEBUG_FMT("Error: {}", e.what());
185 ctx.rpc_ctx->set_apply_writes(true);
186 detail::set_gov_error(
187 ctx.rpc_ctx,
188 HTTP_STATUS_INTERNAL_SERVER_ERROR,
189 errors::InternalError,
190 error_msg);
191 return;
192 }
193 }
194
195 auto response_body = nlohmann::json::object();
196 response_body["message"] = message;
197 response_body["submittedCount"] = submitted_shares_count;
198 response_body["recoveryThreshold"] = threshold;
199
200 ctx.rpc_ctx->set_response_json(response_body, HTTP_STATUS_OK);
201 return;
202 }
203 }
204 };
205 registry
207 "/recovery/members/{memberId}:recover",
208 HTTP_POST,
209 api_version_adapter(submit_recovery_share),
211 .set_openapi_hidden(true)
212 .install();
213 }
214}
Definition node_operation_interface.h:22
Definition base_endpoint_registry.h:121
static std::optional< ServiceStatus > get_service_status(ccf::kv::ReadOnlyTx &tx)
Definition internal_tables_access.h:401
static size_t get_recovery_threshold(ccf::kv::ReadOnlyTx &tx)
Definition internal_tables_access.h:583
Definition share_manager.h:155
static std::optional< EncryptedShare > get_encrypted_share(ccf::kv::ReadOnlyTx &tx, const MemberId &member_id)
Definition share_manager.h:437
size_t submit_recovery_share(ccf::kv::Tx &tx, MemberId member_id, const std::vector< uint8_t > &submitted_recovery_share)
Definition share_manager.h:545
static void clear_submitted_recovery_shares(ccf::kv::Tx &tx)
Definition share_manager.h:567
virtual Endpoint make_endpoint(const std::string &method, RESTVerb verb, const EndpointFunction &f, const AuthnPolicies &ap)
Definition endpoint_registry.cpp:204
virtual Endpoint make_read_only_endpoint(const std::string &method, RESTVerb verb, const ReadOnlyEndpointFunction &f, const AuthnPolicies &ap)
Definition endpoint_registry.cpp:235
#define GOV_FAIL_FMT
Definition gov_logging.h:16
#define GOV_DEBUG_FMT
Definition gov_logging.h:9
#define GOV_INFO_FMT
Definition gov_logging.h:15
std::vector< uint8_t > raw_from_b64(const std::string_view &b64_string)
Definition base64.cpp:12
std::string b64_from_raw(const uint8_t *data, size_t size)
Definition base64.cpp:39
bool try_parse_member_id(const std::shared_ptr< ccf::RpcContext > &rpc_ctx, ccf::MemberId &member_id)
Definition helpers.h:63
AuthnPolicies active_member_sig_only_policies(const std::string &gov_msg_type)
Definition helpers.h:16
Definition api_version.h:11
void init_recovery_handlers(ccf::BaseEndpointRegistry &registry, ShareManager &share_manager, ccf::AbstractNodeContext &node_context)
Definition recovery.h:12
auto api_version_adapter(Fn &&f, ApiVersion min_accepted=ApiVersion::MIN)
Definition api_version.h:101
ApiVersion
Definition api_version.h:13
Definition node_context.h:12
std::shared_ptr< T > get_subsystem(const std::string &name) const
Definition node_context.h:37
Endpoint & set_openapi_hidden(bool hidden)
Definition endpoint.cpp:8
void install()
Definition endpoint.cpp:120