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