CCF
Loading...
Searching...
No Matches
generic_serialise_wrapper.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
5#include "ccf/ccf_assert.h"
7#include "kv_types.h"
8#include "node/rpc/claims.h"
10
11#include <optional>
12
13namespace ccf::kv
14{
17
18 template <typename W>
20 {
21 private:
22 W public_writer;
23 W private_writer;
24 W* current_writer;
25 TxID tx_id;
26 EntryType entry_type;
27 SerialisedEntryFlags header_flags;
28
29 std::shared_ptr<AbstractTxEncryptor> crypto_util;
30
31 // must only be set by set_current_domain, since it affects current_writer
32 SecurityDomain current_domain;
33
34 // If true, consider historical ledger secrets when encrypting entries
35 bool historical_hint;
36
37 template <typename T>
38 void serialise_internal(const T& t)
39 {
40 current_writer->append(t);
41 }
42
43 void set_current_domain(SecurityDomain domain)
44 {
45 switch (domain)
46 {
48 current_writer = &private_writer;
49 current_domain = SecurityDomain::PRIVATE;
50 break;
52 current_writer = &public_writer;
53 current_domain = SecurityDomain::PUBLIC;
54 break;
55 default:
56 break;
57 }
58 }
59
60 public:
62 std::shared_ptr<AbstractTxEncryptor> e,
63 const TxID& tx_id_,
64 EntryType entry_type_,
65 SerialisedEntryFlags header_flags_,
66 // The evidence and claims digest must be systematically present
67 // in regular transactions, but absent in snapshots.
68 const ccf::crypto::Sha256Hash& commit_evidence_digest_ = {},
69 const ccf::ClaimsDigest& claims_digest_ = ccf::no_claims(),
70 bool historical_hint_ = false) :
71 tx_id(tx_id_),
72 entry_type(entry_type_),
73 header_flags(header_flags_),
74 crypto_util(e),
75 historical_hint(historical_hint_)
76 {
77 set_current_domain(SecurityDomain::PUBLIC);
78 serialise_internal(entry_type);
79 serialise_internal(tx_id.version);
80 if (has_claims(entry_type))
81 {
82 serialise_internal(claims_digest_.value());
83 }
84 if (has_commit_evidence(entry_type))
85 {
86 serialise_internal(commit_evidence_digest_);
87 }
88 // Write a placeholder max_conflict_version for compatibility
89 serialise_internal((Version)0u);
90 }
91
92 void start_map(const std::string& name, SecurityDomain domain)
93 {
94 if (domain == SecurityDomain::PRIVATE && !crypto_util)
95 {
96 throw KvSerialiserException(fmt::format(
97 "Private map {} cannot be serialised without an encryptor", name));
98 }
99
100 if (domain != current_domain)
101 {
102 set_current_domain(domain);
103 }
104
105 serialise_internal(name);
106 }
107
108 void serialise_raw(const std::vector<uint8_t>& raw)
109 {
110 serialise_internal(raw);
111 }
112
113 void serialise_view_history(const std::vector<Version>& view_history)
114 {
115 serialise_internal(view_history);
116 }
117
118 template <class Version>
119 void serialise_entry_version(const Version& version)
120 {
121 serialise_internal(version);
122 }
123
124 void serialise_count_header(uint64_t ctr)
125 {
126 serialise_internal(ctr);
127 }
128
129 void serialise_read(const SerialisedKey& k, const Version& version)
130 {
131 serialise_internal(k);
132 serialise_internal(version);
133 }
134
136 {
137 serialise_internal(k);
138 serialise_internal(v);
139 }
140
142 {
143 serialise_internal(k);
144 }
145
146 std::vector<uint8_t> get_raw_data()
147 {
148 // make sure the private buffer is empty when we return
149 auto writer_guard_func = [](W* writer) { writer->clear(); };
150 std::unique_ptr<decltype(private_writer), decltype(writer_guard_func)>
151 writer_guard(&private_writer, writer_guard_func);
152
153 return serialise_domains(
154 public_writer.get_raw_data(), private_writer.get_raw_data());
155 }
156
157 std::vector<uint8_t> serialise_domains(
158 const std::vector<uint8_t>& serialised_public_domain,
159 const std::vector<uint8_t>& serialised_private_domain =
160 std::vector<uint8_t>())
161 {
162 size_t size_ = serialised_public_domain.size();
163
164 SerialisedEntryHeader entry_header;
165 entry_header.version = entry_format_v1;
166 entry_header.flags = header_flags;
167
168 // If no crypto util is set (unit test only), only the header and public
169 // domain are serialised
170 if (crypto_util)
171 {
172 size_ += crypto_util->get_header_length() + sizeof(size_t) +
173 serialised_private_domain.size();
174 }
175 entry_header.set_size(size_);
176
177 size_ += sizeof(SerialisedEntryHeader);
178
179 std::vector<uint8_t> entry(size_);
180 auto data_ = entry.data();
181
182 serialized::write(data_, size_, entry_header);
183
184 if (!crypto_util)
185 {
187 serialised_private_domain.empty(),
188 "Serialised does not have a crypto util but some private data were "
189 "serialised");
191 data_,
192 size_,
193 serialised_public_domain.data(),
194 serialised_public_domain.size());
195
196 return entry;
197 }
198
199 std::vector<uint8_t> serialised_hdr;
200 std::vector<uint8_t> encrypted_private_domain(
201 serialised_private_domain.size());
202
203 if (!crypto_util->encrypt(
204 serialised_private_domain,
205 serialised_public_domain,
206 serialised_hdr,
207 encrypted_private_domain,
208 tx_id,
209 entry_type,
210 historical_hint))
211 {
212 throw KvSerialiserException(fmt::format(
213 "Could not serialise transaction at seqno {}", tx_id.version));
214 }
215
217 data_, size_, serialised_hdr.data(), serialised_hdr.size());
218 serialized::write(data_, size_, serialised_public_domain.size());
220 data_,
221 size_,
222 serialised_public_domain.data(),
223 serialised_public_domain.size());
224 if (encrypted_private_domain.size() > 0)
225 {
227 data_,
228 size_,
229 encrypted_private_domain.data(),
230 encrypted_private_domain.size());
231 }
232
233 return entry;
234 }
235 };
236
237 template <typename R>
239 {
240 private:
241 R public_reader;
242 R private_reader;
243 R* current_reader;
244 std::vector<uint8_t> decrypted_buffer;
245 EntryType entry_type;
246 // Present systematically in regular transactions, but absent from snapshots
247 ccf::ClaimsDigest claims_digest = ccf::no_claims();
248 // Present systematically in regular transactions, but absent from snapshots
249 std::optional<ccf::crypto::Sha256Hash> commit_evidence_digest =
250 std::nullopt;
251 Version version;
252 std::shared_ptr<AbstractTxEncryptor> crypto_util;
253 std::optional<SecurityDomain> domain_restriction;
254
255 // Should only be called once, once the GCM header and length of public
256 // domain have been read
257 void read_public_header()
258 {
259 entry_type = public_reader.template read_next<EntryType>();
260 version = public_reader.template read_next<Version>();
261 if (has_claims(entry_type))
262 {
263 auto digest_array =
264 public_reader
265 .template read_next<ccf::ClaimsDigest::Digest::Representation>();
266 claims_digest.set(std::move(digest_array));
267 }
268 if (has_commit_evidence(entry_type))
269 {
270 auto digest_array =
271 public_reader
272 .template read_next<ccf::crypto::Sha256Hash::Representation>();
273 commit_evidence_digest =
275 }
276 // max_conflict_version is included for compatibility, but currently
277 // ignored
278 const auto _ = public_reader.template read_next<Version>();
279 }
280
281 public:
283 std::shared_ptr<AbstractTxEncryptor> e,
284 std::optional<SecurityDomain> domain_restriction = std::nullopt) :
285 crypto_util(e),
286 domain_restriction(domain_restriction)
287 {}
288
290 {
291 return std::move(claims_digest);
292 }
293
294 std::optional<ccf::crypto::Sha256Hash>&& consume_commit_evidence_digest()
295 {
296 return std::move(commit_evidence_digest);
297 }
298
299 std::optional<Version> init(
300 const uint8_t* data,
301 size_t size,
302 ccf::kv::Term& term,
303 bool historical_hint = false)
304 {
305 current_reader = &public_reader;
306 auto data_ = data;
307 auto size_ = size;
308
309 const auto tx_header =
310 serialized::read<SerialisedEntryHeader>(data_, size_);
311
312 if (tx_header.size != size_)
313 {
314 throw std::logic_error(fmt::format(
315 "Reported size in entry header {} does not match size of entry {}",
316 tx_header.size,
317 size_));
318 }
319
320 auto gcm_hdr_data = data_;
321
322 switch (tx_header.version)
323 {
324 case entry_format_v1:
325 {
326 // Proceed with deserialisation
327 break;
328 }
329 default:
330 {
331 throw std::logic_error(fmt::format(
332 "Cannot deserialise entry format {}", tx_header.version));
333 }
334 }
335
336 // If the kv store has no encryptor, assume that the serialised tx is
337 // public only with no header (test only)
338 if (!crypto_util)
339 {
340 public_reader.init(data_, size_);
341 read_public_header();
342 return version;
343 }
344
345 serialized::skip(data_, size_, crypto_util->get_header_length());
346 auto public_domain_length = serialized::read<size_t>(data_, size_);
347
348 auto data_public = data_;
349 public_reader.init(data_public, public_domain_length);
350 read_public_header();
351
352 // If the domain is public only, skip the decryption and only return the
353 // public data (integrity will be verified at the next signature entry)
354 if (
355 domain_restriction.has_value() &&
356 domain_restriction.value() == SecurityDomain::PUBLIC)
357 {
358 // Retrieve term from GCM header, even if the domain restriction is set
359 // to public and the decryption is skipped, so that the term for the
360 // deserialised entry can be reported
361 term =
362 crypto_util->get_term(gcm_hdr_data, crypto_util->get_header_length());
363
364 return version;
365 }
366
367 serialized::skip(data_, size_, public_domain_length);
368 decrypted_buffer.resize(size_);
369
370 if (!crypto_util->decrypt(
371 {data_, data_ + size_},
372 {data_public, data_public + public_domain_length},
373 {gcm_hdr_data, gcm_hdr_data + crypto_util->get_header_length()},
374 decrypted_buffer,
375 version,
376 term,
377 historical_hint))
378 {
379 return std::nullopt;
380 }
381
382 private_reader.init(decrypted_buffer.data(), decrypted_buffer.size());
383 return version;
384 }
385
386 std::optional<std::string> start_map()
387 {
388 if (current_reader->is_eos())
389 {
390 if (current_reader == &public_reader && !private_reader.is_eos())
391 {
392 current_reader = &private_reader;
393 }
394 else
395 {
396 return std::nullopt;
397 }
398 }
399
400 return current_reader->template read_next<std::string>();
401 }
402
404 {
405 return current_reader->template read_next<Version>();
406 }
407
409 {
410 return current_reader->template read_next<uint64_t>();
411 }
412
413 std::tuple<SerialisedKey, Version> deserialise_read()
414 {
415 return {
416 current_reader->template read_next<SerialisedKey>(),
417 current_reader->template read_next<Version>()};
418 }
419
421 {
422 return current_reader->template read_next<uint64_t>();
423 }
424
425 std::tuple<SerialisedKey, SerialisedValue> deserialise_write()
426 {
427 return {
428 current_reader->template read_next<SerialisedKey>(),
429 current_reader->template read_next<SerialisedValue>()};
430 }
431
432 std::vector<uint8_t> deserialise_raw()
433 {
434 return current_reader->template read_next<std::vector<uint8_t>>();
435 }
436
437 std::vector<Version> deserialise_view_history()
438 {
439 return current_reader->template read_next<std::vector<Version>>();
440 }
441
443 {
444 return current_reader->template read_next<uint64_t>();
445 }
446
448 {
449 return current_reader->template read_next<SerialisedKey>();
450 }
451
452 bool end()
453 {
454 return current_reader->is_eos() && public_reader.is_eos();
455 }
456 };
457}
#define CCF_ASSERT_FMT(expr,...)
Definition ccf_assert.h:10
Definition claims_digest.h:10
void set(Digest &&digest_)
Definition claims_digest.h:21
const Digest & value() const
Definition claims_digest.h:38
Definition sha256_hash.h:16
static Sha256Hash from_representation(const Representation &r)
Definition sha256_hash.cpp:80
Definition generic_serialise_wrapper.h:239
std::optional< Version > init(const uint8_t *data, size_t size, ccf::kv::Term &term, bool historical_hint=false)
Definition generic_serialise_wrapper.h:299
std::tuple< SerialisedKey, Version > deserialise_read()
Definition generic_serialise_wrapper.h:413
std::vector< uint8_t > deserialise_raw()
Definition generic_serialise_wrapper.h:432
std::tuple< SerialisedKey, SerialisedValue > deserialise_write()
Definition generic_serialise_wrapper.h:425
GenericDeserialiseWrapper(std::shared_ptr< AbstractTxEncryptor > e, std::optional< SecurityDomain > domain_restriction=std::nullopt)
Definition generic_serialise_wrapper.h:282
uint64_t deserialise_write_header()
Definition generic_serialise_wrapper.h:420
ccf::ClaimsDigest && consume_claims_digest()
Definition generic_serialise_wrapper.h:289
uint64_t deserialise_remove_header()
Definition generic_serialise_wrapper.h:442
std::optional< std::string > start_map()
Definition generic_serialise_wrapper.h:386
std::vector< Version > deserialise_view_history()
Definition generic_serialise_wrapper.h:437
uint64_t deserialise_read_header()
Definition generic_serialise_wrapper.h:408
bool end()
Definition generic_serialise_wrapper.h:452
Version deserialise_entry_version()
Definition generic_serialise_wrapper.h:403
SerialisedKey deserialise_remove()
Definition generic_serialise_wrapper.h:447
std::optional< ccf::crypto::Sha256Hash > && consume_commit_evidence_digest()
Definition generic_serialise_wrapper.h:294
Definition generic_serialise_wrapper.h:20
std::vector< uint8_t > get_raw_data()
Definition generic_serialise_wrapper.h:146
std::vector< uint8_t > serialise_domains(const std::vector< uint8_t > &serialised_public_domain, const std::vector< uint8_t > &serialised_private_domain=std::vector< uint8_t >())
Definition generic_serialise_wrapper.h:157
void serialise_count_header(uint64_t ctr)
Definition generic_serialise_wrapper.h:124
void serialise_remove(const SerialisedKey &k)
Definition generic_serialise_wrapper.h:141
void serialise_view_history(const std::vector< Version > &view_history)
Definition generic_serialise_wrapper.h:113
void serialise_raw(const std::vector< uint8_t > &raw)
Definition generic_serialise_wrapper.h:108
void start_map(const std::string &name, SecurityDomain domain)
Definition generic_serialise_wrapper.h:92
GenericSerialiseWrapper(std::shared_ptr< AbstractTxEncryptor > e, const TxID &tx_id_, EntryType entry_type_, SerialisedEntryFlags header_flags_, const ccf::crypto::Sha256Hash &commit_evidence_digest_={}, const ccf::ClaimsDigest &claims_digest_=ccf::no_claims(), bool historical_hint_=false)
Definition generic_serialise_wrapper.h:61
void serialise_entry_version(const Version &version)
Definition generic_serialise_wrapper.h:119
void serialise_read(const SerialisedKey &k, const Version &version)
Definition generic_serialise_wrapper.h:129
void serialise_write(const SerialisedKey &k, const SerialisedValue &v)
Definition generic_serialise_wrapper.h:135
Definition kv_types.h:352
ccf::ByteVector SerialisedEntry
Definition serialised_entry.h:8
Definition app_interface.h:20
ccf::kv::serialisers::SerialisedEntry SerialisedKey
Definition generic_serialise_wrapper.h:15
ccf::kv::serialisers::SerialisedEntry SerialisedValue
Definition generic_serialise_wrapper.h:16
uint64_t Term
Definition kv_types.h:46
SecurityDomain
Definition kv_types.h:253
@ PRIVATE
Definition kv_types.h:255
@ PUBLIC
Definition kv_types.h:254
EntryType
Definition kv_types.h:267
uint64_t Version
Definition version.h:8
uint8_t SerialisedEntryFlags
Definition serialised_entry_format.h:12
void write(uint8_t *&data, size_t &size, const T &v)
Definition serialized.h:106
void skip(const uint8_t *&data, size_t &size, size_t skip)
Definition serialized.h:166
Definition serialised_entry_format.h:24
void set_size(uint64_t size_)
Definition serialised_entry_format.h:32
uint8_t version
Definition serialised_entry_format.h:25
SerialisedEntryFlags flags
Definition serialised_entry_format.h:26
Definition kv_types.h:50
Version version
Definition kv_types.h:52