CCF
Loading...
Searching...
No Matches
local_sealing.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
6#include "ccf/ds/json.h"
7#include "ccf/ds/logger.h"
8#include "ccf/kv/version.h"
10#include "ccf/pal/snp_ioctl.h"
11#include "ds/ccf_assert.h"
12#include "ds/files.h"
13#include "node/ledger_secret.h"
14#include "node/ledger_secrets.h"
15
16#include <algorithm>
17#include <filesystem>
18#include <fmt/format.h>
19#include <map>
20#include <optional>
21#include <ranges>
22
23namespace ccf
24{
25
26 inline std::string get_sealing_filename(const kv::Version& version)
27 {
28 return fmt::format("{}.sealed.json", version);
29 }
30
31 inline std::optional<kv::Version> version_of_filename(const std::string& path)
32 {
33 auto pos = path.find_first_of('.');
34 if (pos == std::string::npos)
35 {
36 throw std::logic_error(fmt::format(
37 "Sealed ledger secret file name {} does not contain a version", path));
38 }
39
40 try
41 {
42 return std::stol(path.substr(0, pos));
43 }
44 catch (const std::invalid_argument& e)
45 {
47 "Unable to parse version from file name {}, {}", path, e.what());
48 return std::nullopt;
49 }
50 }
51
53 std::span<const uint8_t> raw_key,
54 std::span<const uint8_t> plaintext,
55 const std::span<uint8_t>& aad)
56 {
58 auto key = ccf::crypto::make_key_aes_gcm(raw_key);
59
60 crypto::GcmCipher cipher(plaintext.size());
61 cipher.hdr.set_random_iv();
62
63 key->encrypt(cipher.hdr.iv, plaintext, aad, cipher.cipher, cipher.hdr.tag);
64 return cipher;
65 }
66
67 inline std::vector<uint8_t> aes_gcm_unsealing(
68 std::span<const uint8_t> raw_key,
69 const std::vector<uint8_t>& sealed_text,
70 const std::span<uint8_t>& aad)
71 {
73 auto key = ccf::crypto::make_key_aes_gcm(raw_key);
74
75 crypto::GcmCipher cipher;
76 cipher.deserialise(sealed_text);
77
78 std::vector<uint8_t> plaintext;
79 if (!key->decrypt(
80 cipher.hdr.get_iv(), cipher.hdr.tag, cipher.cipher, aad, plaintext))
81 {
82 throw std::logic_error("Failed to decrypt sealed data");
83 }
84
85 return plaintext;
86 }
87
93
97
99 {
100 std::vector<uint8_t> ciphertext;
101 std::string aad_text;
102 };
103
106
108 const std::string& sealed_secret_dir,
109 const ccf::pal::snp::TcbVersionRaw& tcb_version,
110 const kv::Version& version,
111 const LedgerSecretPtr& ledger_secret)
112 {
113 LOG_INFO_FMT("Sealing ledger secret to {}", sealed_secret_dir);
114
115 files::create_directory(sealed_secret_dir);
116
117 std::string plaintext = nlohmann::json(ledger_secret).dump();
118 std::vector<uint8_t> buf_plaintext(plaintext.begin(), plaintext.end());
119
120 std::string plainaad =
121 nlohmann::json(
122 SealedLedgerSecretAAD{.version = version, .tcb_version = tcb_version})
123 .dump();
124 std::vector<uint8_t> buf_aad(plainaad.begin(), plainaad.end());
125
126 // prevent unsealing if the TCB rolls back
127 auto sealing_key = ccf::pal::snp::make_derived_key(tcb_version);
128 crypto::GcmCipher sealed_secret =
129 aes_gcm_sealing(sealing_key->get_raw(), buf_plaintext, buf_aad);
130
131 auto dir_path = files::fs::path(sealed_secret_dir);
132 auto sealing_path = dir_path / get_sealing_filename(version);
133 SealedLedgerSecret sealed_secret_for_store = {
134 .ciphertext = sealed_secret.serialise(), .aad_text = plainaad};
135
136 files::dump(nlohmann::json(sealed_secret_for_store).dump(), sealing_path);
137 LOG_INFO_FMT("Sealing complete of ledger secret to {}", sealing_path);
138 }
139
140 inline std::optional<LedgerSecretPtr> unseal_ledger_secret_from_disk(
141 ccf::kv::Version expected_version,
142 const files::fs::path& ledger_secret_path)
143 {
144 try
145 {
147 files::exists(ledger_secret_path),
148 "Sealed previous ledger secret cannot be found");
149
151 "Reading sealed previous service secret from {}", ledger_secret_path);
152 std::vector<uint8_t> sealed_secret_raw = files::slurp(ledger_secret_path);
153 SealedLedgerSecret sealed_ledger_secret = nlohmann::json::parse(
154 std::string(sealed_secret_raw.begin(), sealed_secret_raw.end()));
156 nlohmann::json::parse(sealed_ledger_secret.aad_text);
157
159 aad.version == expected_version,
160 "Sealed ledger secret version {} does not match expected version {}",
161 aad.version,
162 expected_version);
163
164 // make_derived_key will fail if the CPU's TCB version is rolled back
165 // below aad.tcb_version
166 auto sealing_key = ccf::pal::snp::make_derived_key(aad.tcb_version);
167 std::vector<uint8_t> buf_aad(
168 sealed_ledger_secret.aad_text.begin(),
169 sealed_ledger_secret.aad_text.end());
170
171 auto buf_plaintext = aes_gcm_unsealing(
172 sealing_key->get_raw(), sealed_ledger_secret.ciphertext, buf_aad);
173
174 LedgerSecret unsealed_ledger_secret = nlohmann::json::parse(
175 std::string(buf_plaintext.begin(), buf_plaintext.end()));
176
177 LOG_INFO_FMT("Successfully unsealed secret");
178
179 return std::make_shared<LedgerSecret>(std::move(unsealed_ledger_secret));
180 }
181 catch (const std::logic_error& e)
182 {
184 "Failed to unseal previous ledger secret from {}: {}",
185 ledger_secret_path,
186 e.what());
187 return std::nullopt;
188 }
189 }
190
192 const std::string& sealed_secret_dir, kv::Version max_version)
193 {
194 std::vector<std::pair<kv::Version, std::filesystem::path>> files;
195 std::map<kv::Version, std::filesystem::path> files_map;
196 for (auto f : files::fs::directory_iterator(sealed_secret_dir))
197 {
198 auto filename = f.path().filename();
199 std::optional<kv::Version> ledger_version =
200 version_of_filename(filename.string());
201 if (ledger_version.has_value() && ledger_version.value() <= max_version)
202 {
203 files_map[ledger_version.value()] = f.path();
204 }
205 }
206
207 for (auto& [version, sealed_path] : std::ranges::reverse_view(files_map))
208 {
209 auto unsealed = unseal_ledger_secret_from_disk(version, sealed_path);
210 if (unsealed.has_value())
211 {
213 "Successfully unsealed ledger secret from {}", sealed_path.string());
214 return unsealed.value();
215 }
216 }
217
218 // No valid ledger secret has been unsealed
219 throw std::logic_error(fmt::format(
220 "Failed to unseal any ledger secret from {}", sealed_secret_dir));
221 }
222}
#define CCF_ASSERT_FMT(expr,...)
Definition ccf_assert.h:10
#define CCF_ASSERT(expr, msg)
Definition ccf_assert.h:14
#define DECLARE_JSON_REQUIRED_FIELDS(TYPE,...)
Definition json.h:714
#define DECLARE_JSON_TYPE(TYPE)
Definition json.h:663
#define DECLARE_JSON_TYPE_WITH_OPTIONAL_FIELDS(TYPE)
Definition json.h:690
#define DECLARE_JSON_OPTIONAL_FIELDS(TYPE,...)
Definition json.h:786
#define LOG_INFO_FMT
Definition logger.h:362
#define LOG_FAIL_FMT
Definition logger.h:363
void check_supported_aes_key_size(size_t num_bits)
Definition symmetric_key.h:100
std::unique_ptr< KeyAesGcm > make_key_aes_gcm(std::span< const uint8_t > rawKey)
Free function implementation.
Definition symmetric_key.cpp:102
uint64_t Version
Definition version.h:8
Definition app_interface.h:14
std::optional< LedgerSecretPtr > unseal_ledger_secret_from_disk(ccf::kv::Version expected_version, const files::fs::path &ledger_secret_path)
Definition local_sealing.h:140
LedgerSecretPtr find_and_unseal_ledger_secret_from_disk(const std::string &sealed_secret_dir, kv::Version max_version)
Definition local_sealing.h:191
std::string get_sealing_filename(const kv::Version &version)
Definition local_sealing.h:26
std::vector< uint8_t > aes_gcm_unsealing(std::span< const uint8_t > raw_key, const std::vector< uint8_t > &sealed_text, const std::span< uint8_t > &aad)
Definition local_sealing.h:67
std::shared_ptr< LedgerSecret > LedgerSecretPtr
Definition ledger_secret.h:75
crypto::GcmCipher aes_gcm_sealing(std::span< const uint8_t > raw_key, std::span< const uint8_t > plaintext, const std::span< uint8_t > &aad)
Definition local_sealing.h:52
void seal_ledger_secret_to_disk(const std::string &sealed_secret_dir, const ccf::pal::snp::TcbVersionRaw &tcb_version, const kv::Version &version, const LedgerSecretPtr &ledger_secret)
Definition local_sealing.h:107
std::optional< kv::Version > version_of_filename(const std::string &path)
Definition local_sealing.h:31
Definition files.h:20
Definition ledger_secret.h:19
Definition local_sealing.h:89
ccf::pal::snp::TcbVersionRaw tcb_version
Definition local_sealing.h:91
ccf::kv::Version version
Definition local_sealing.h:90
Definition local_sealing.h:99
std::vector< uint8_t > ciphertext
Definition local_sealing.h:100
std::string aad_text
Definition local_sealing.h:101
void set_random_iv(EntropyPtr entropy=ccf::crypto::get_entropy())
Definition symmetric_key.h:47
Definition symmetric_key.h:57
void deserialise(const std::vector< uint8_t > &serial)
Definition symmetric_key.cpp:93
std::vector< uint8_t > serialise()
Definition symmetric_key.cpp:78
StandardGcmHeader hdr
Definition symmetric_key.h:58
std::vector< uint8_t > cipher
Definition symmetric_key.h:59
uint8_t tag[GCM_SIZE_TAG]
Definition symmetric_key.h:18
std::vector< uint8_t > iv
Definition symmetric_key.h:21
std::span< const uint8_t > get_iv() const
Definition symmetric_key.cpp:34
Definition attestation_sev_snp.h:199