170 std::shared_ptr<LedgerSecrets> ledger_secrets;
178 auto active_recovery_participants_info =
181 size_t share_index = 0;
182 for (
auto const& [member_id, enc_pub_key] :
183 active_recovery_participants_info)
186 auto raw_share = std::vector<uint8_t>(
187 shares[share_index].begin(), shares[share_index].end());
188 encrypted_shares[member_id] = member_enc_pubk->rsa_oaep_wrap(raw_share);
189 OPENSSL_cleanse(raw_share.data(), raw_share.size());
190 OPENSSL_cleanse(shares[share_index].data(), shares[share_index].size());
194 auto active_recovery_owners_info =
196 if (!active_recovery_owners_info.empty())
198 std::vector<uint8_t> full_share_serialised(
202 for (
auto const& [member_id, enc_pub_key] : active_recovery_owners_info)
205 encrypted_shares[member_id] =
206 member_enc_pubk->rsa_oaep_wrap(full_share_serialised);
210 full_share_serialised.data(), full_share_serialised.size());
213 return encrypted_shares;
216 void shuffle_recovery_shares(
219 auto active_recovery_participants_info =
221 auto active_recovery_owners_info =
223 size_t recovery_threshold =
227 active_recovery_participants_info.empty() &&
228 active_recovery_owners_info.empty())
230 throw std::logic_error(
231 "There should be at least one active recovery member to issue "
235 if (recovery_threshold == 0)
237 throw std::logic_error(
238 "Recovery threshold should be set before recovery "
239 "shares are computed");
242 size_t num_shares = 0;
243 if (!active_recovery_participants_info.empty())
245 if (recovery_threshold > active_recovery_participants_info.size())
247 throw std::logic_error(fmt::format(
248 "Recovery threshold {} should be equal to or less than the number "
249 "of active recovery members {}",
251 active_recovery_participants_info.size()));
254 num_shares = active_recovery_participants_info.size();
258 if (recovery_threshold > 1)
260 throw std::logic_error(fmt::format(
261 "Recovery threshold {} cannot be greater than 1 when the "
262 "consortium consists of only active recovery owner members ({})",
264 active_recovery_owners_info.size()));
270 auto ls_wrapping_key =
273 auto wrapped_latest_ls = ls_wrapping_key.
wrap(latest_ledger_secret);
274 auto* recovery_shares = tx.
rw<ccf::RecoveryShares>(Tables::SHARES);
275 recovery_shares->put(
277 compute_encrypted_shares(tx, ls_wrapping_key),
278 latest_ledger_secret->previous_secret_stored_version});
281 void set_recovery_shares_info(
284 const std::optional<VersionedLedgerSecret>& previous_ledger_secret =
286 std::optional<ccf::kv::Version> latest_ls_version = std::nullopt)
295 shuffle_recovery_shares(tx, latest_ledger_secret);
298 Tables::ENCRYPTED_PAST_LEDGER_SECRET);
300 std::vector<uint8_t> encrypted_previous_secret = {};
302 if (previous_ledger_secret.has_value())
304 version_previous_secret = previous_ledger_secret->first;
307 previous_ledger_secret->second->raw_key.size());
310 latest_ledger_secret->key->encrypt(
312 previous_ledger_secret->second->raw_key,
314 encrypted_previous_ls.
cipher,
315 encrypted_previous_ls.
hdr.
tag);
317 encrypted_previous_secret = encrypted_previous_ls.
serialise();
320 std::move(encrypted_previous_secret),
321 version_previous_secret,
322 encrypted_ls->get_version_of_previous_write()),
327 encrypted_ls->put({std::nullopt, latest_ls_version});
331 std::vector<uint8_t> encrypt_submitted_share(
332 const std::vector<uint8_t>& submitted_share,
340 current_ledger_secret->key->encrypt(
344 encrypted_submitted_share.
cipher,
345 encrypted_submitted_share.
hdr.
tag);
347 return encrypted_submitted_share.
serialise();
350 std::vector<uint8_t> decrypt_submitted_share(
351 const std::vector<uint8_t>& encrypted_submitted_share,
355 encrypted_share.
deserialise(encrypted_submitted_share);
356 std::vector<uint8_t> decrypted_share;
358 if (!current_ledger_secret->key->decrypt(
365 throw std::logic_error(
"Decrypting submitted shares failed");
368 return decrypted_share;
372 combine_from_encrypted_submitted_shares(
ccf::kv::Tx& tx)
375 Tables::ENCRYPTED_SUBMITTED_SHARES);
376 auto* config = tx.
rw<ccf::Configuration>(Tables::CONFIGURATION);
378 std::optional<ccf::crypto::sharing::Share> full_share;
379 std::vector<ccf::crypto::sharing::Share> new_shares = {};
380 encrypted_submitted_shares->foreach(
381 [&new_shares, &full_share, &tx,
this](
383 auto decrypted_share = decrypt_submitted_share(
384 encrypted_share, ledger_secrets->get_latest(tx).second);
385 switch (decrypted_share.size())
401 new_shares.emplace_back(decrypted_share);
407 OPENSSL_cleanse(decrypted_share.data(), decrypted_share.size());
408 throw std::logic_error(fmt::format(
409 "Error combining recovery shares: decrypted share of {} bytes "
410 "is not an {}-byte long new-style share.",
411 decrypted_share.size(),
415 OPENSSL_cleanse(decrypted_share.data(), decrypted_share.size());
416 return !full_share.has_value();
419 if (full_share.has_value())
421 return {full_share.value()};
424 auto num_shares = new_shares.size();
426 auto config_val = config->get();
427 if (!config_val.has_value())
429 throw std::logic_error(
"Configuration is not set");
431 auto recovery_threshold = config_val->recovery_threshold;
432 if (recovery_threshold > num_shares)
434 throw std::logic_error(fmt::format(
435 "Error combining recovery shares: only {} recovery shares were "
436 "submitted but recovery threshold is {}",
438 recovery_threshold));
441 return {std::move(new_shares), recovery_threshold};
446 ledger_secrets(ledger_secrets_)
457 auto [latest, penultimate] =
458 ledger_secrets->get_latest_and_penultimate(tx);
460 set_recovery_shares_info(tx, latest.second, penultimate, latest.first);
477 set_recovery_shares_info(
478 tx, new_ledger_secret, ledger_secrets->get_latest(tx));
489 shuffle_recovery_shares(tx, ledger_secrets->get_latest(tx).second);
495 auto recovery_shares_info =
496 tx.
ro<ccf::RecoveryShares>(Tables::SHARES)->get();
497 if (!recovery_shares_info.has_value())
499 throw std::logic_error(
500 "Failed to retrieve current recovery shares info");
503 auto search = recovery_shares_info->encrypted_shares.find(member_id);
504 if (search == recovery_shares_info->encrypted_shares.end())
509 return search->second;
515 const std::optional<LedgerSecretPtr>& restored_ls_opt = std::nullopt)
517 if (recovery_ledger_secrets.empty())
519 throw std::logic_error(
"No recovery ledger secrets");
523 if (restored_ls_opt.has_value())
525 restored_ls = restored_ls_opt.value();
533 auto recovery_shares_info =
534 tx.
ro<ccf::RecoveryShares>(Tables::SHARES)->get();
535 if (!recovery_shares_info.has_value())
537 throw std::logic_error(
538 "Failed to retrieve current recovery shares info");
541 restored_ls = combine_from_encrypted_submitted_shares(tx).
unwrap(
542 recovery_shares_info->wrapped_latest_ledger_secret);
546 "Recovering {} encrypted ledger secrets",
547 recovery_ledger_secrets.size());
549 const auto& current_ledger_secret_version =
550 recovery_ledger_secrets.back().next_version;
551 if (!current_ledger_secret_version.has_value())
555 throw std::logic_error(
"Current ledger secret version should be set");
558 auto* encrypted_previous_ledger_secret =
560 Tables::ENCRYPTED_PAST_LEDGER_SECRET);
563 auto s = restored_ledger_secrets.emplace(
564 current_ledger_secret_version.value(),
565 std::make_shared<LedgerSecret>(
566 std::move(restored_ls->raw_key),
567 encrypted_previous_ledger_secret->get_version_of_previous_write()));
568 auto latest_ls = s.first->second;
570 for (
const auto& recovery_ledger_secret :
571 std::ranges::reverse_view(recovery_ledger_secrets))
573 if (!recovery_ledger_secret.previous_ledger_secret.has_value())
579 const auto& prev_secret =
580 recovery_ledger_secret.previous_ledger_secret.value();
583 "Recovering encrypted ledger secret valid at seqno {}",
584 prev_secret.version);
587 restored_ledger_secrets.find(prev_secret.version) !=
588 restored_ledger_secrets.end())
592 "Skipping, already decrypted ledger secret with version {}",
593 prev_secret.version);
598 latest_ls, prev_secret.encrypted_data);
600 auto secret = restored_ledger_secrets.emplace(
602 std::make_shared<LedgerSecret>(
603 std::move(decrypted_ls_raw),
604 prev_secret.previous_secret_stored_version));
605 latest_ls = secret.first->second;
608 return restored_ledger_secrets;
612 const std::vector<uint8_t>& submitted_recovery_share)
615 submitted_recovery_share.size() ==
632 const std::vector<uint8_t>& submitted_recovery_share)
636 Tables::ENCRYPTED_SUBMITTED_SHARES);
637 auto active_service = service->get();
638 if (!active_service.has_value())
640 throw std::logic_error(
"Failed to get active service");
643 encrypted_submitted_shares->put(
645 encrypt_submitted_share(
646 submitted_recovery_share, ledger_secrets->get_latest(tx).second));
648 return encrypted_submitted_shares->size();
654 Tables::ENCRYPTED_SUBMITTED_SHARES);
655 encrypted_submitted_shares->clear();