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 "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 EntryFlags& flags,
304 bool historical_hint = false)
305 {
306 current_reader = &public_reader;
307 auto data_ = data;
308 auto size_ = size;
309
310 const auto tx_header =
311 serialized::read<SerialisedEntryHeader>(data_, size_);
312
313 flags = static_cast<EntryFlags>(tx_header.flags);
314
315 if (tx_header.size != size_)
316 {
317 throw std::logic_error(fmt::format(
318 "Reported size in entry header {} does not match size of entry {}",
319 tx_header.size,
320 size_));
321 }
322
323 auto gcm_hdr_data = data_;
324
325 switch (tx_header.version)
326 {
327 case entry_format_v1:
328 {
329 // Proceed with deserialisation
330 break;
331 }
332 default:
333 {
334 throw std::logic_error(fmt::format(
335 "Cannot deserialise entry format {}", tx_header.version));
336 }
337 }
338
339 // If the kv store has no encryptor, assume that the serialised tx is
340 // public only with no header (test only)
341 if (!crypto_util)
342 {
343 public_reader.init(data_, size_);
344 read_public_header();
345 return version;
346 }
347
348 serialized::skip(data_, size_, crypto_util->get_header_length());
349 auto public_domain_length = serialized::read<size_t>(data_, size_);
350
351 auto data_public = data_;
352 public_reader.init(data_public, public_domain_length);
353 read_public_header();
354
355 // If the domain is public only, skip the decryption and only return the
356 // public data (integrity will be verified at the next signature entry)
357 if (
358 domain_restriction.has_value() &&
359 domain_restriction.value() == SecurityDomain::PUBLIC)
360 {
361 // Retrieve term from GCM header, even if the domain restriction is set
362 // to public and the decryption is skipped, so that the term for the
363 // deserialised entry can be reported
364 term =
365 crypto_util->get_term(gcm_hdr_data, crypto_util->get_header_length());
366
367 return version;
368 }
369
370 serialized::skip(data_, size_, public_domain_length);
371 decrypted_buffer.resize(size_);
372
373 if (!crypto_util->decrypt(
374 {data_, data_ + size_},
375 {data_public, data_public + public_domain_length},
376 {gcm_hdr_data, gcm_hdr_data + crypto_util->get_header_length()},
377 decrypted_buffer,
378 version,
379 term,
380 historical_hint))
381 {
382 return std::nullopt;
383 }
384
385 private_reader.init(decrypted_buffer.data(), decrypted_buffer.size());
386 return version;
387 }
388
389 std::optional<std::string> start_map()
390 {
391 if (current_reader->is_eos())
392 {
393 if (current_reader == &public_reader && !private_reader.is_eos())
394 {
395 current_reader = &private_reader;
396 }
397 else
398 {
399 return std::nullopt;
400 }
401 }
402
403 return current_reader->template read_next<std::string>();
404 }
405
407 {
408 return current_reader->template read_next<Version>();
409 }
410
412 {
413 return current_reader->template read_next<uint64_t>();
414 }
415
416 std::tuple<SerialisedKey, Version> deserialise_read()
417 {
418 return {
419 current_reader->template read_next<SerialisedKey>(),
420 current_reader->template read_next<Version>()};
421 }
422
424 {
425 return current_reader->template read_next<uint64_t>();
426 }
427
428 std::tuple<SerialisedKey, SerialisedValue> deserialise_write()
429 {
430 return {
431 current_reader->template read_next<SerialisedKey>(),
432 current_reader->template read_next<SerialisedValue>()};
433 }
434
435 std::vector<uint8_t> deserialise_raw()
436 {
437 return current_reader->template read_next<std::vector<uint8_t>>();
438 }
439
440 std::vector<Version> deserialise_view_history()
441 {
442 return current_reader->template read_next<std::vector<Version>>();
443 }
444
446 {
447 return current_reader->template read_next<uint64_t>();
448 }
449
451 {
452 return current_reader->template read_next<SerialisedKey>();
453 }
454
455 bool end()
456 {
457 return current_reader->is_eos() && public_reader.is_eos();
458 }
459 };
460}
#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::tuple< SerialisedKey, Version > deserialise_read()
Definition generic_serialise_wrapper.h:416
std::vector< uint8_t > deserialise_raw()
Definition generic_serialise_wrapper.h:435
std::tuple< SerialisedKey, SerialisedValue > deserialise_write()
Definition generic_serialise_wrapper.h:428
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:423
ccf::ClaimsDigest && consume_claims_digest()
Definition generic_serialise_wrapper.h:289
uint64_t deserialise_remove_header()
Definition generic_serialise_wrapper.h:445
std::optional< std::string > start_map()
Definition generic_serialise_wrapper.h:389
std::vector< Version > deserialise_view_history()
Definition generic_serialise_wrapper.h:440
uint64_t deserialise_read_header()
Definition generic_serialise_wrapper.h:411
bool end()
Definition generic_serialise_wrapper.h:455
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:299
Version deserialise_entry_version()
Definition generic_serialise_wrapper.h:406
SerialisedKey deserialise_remove()
Definition generic_serialise_wrapper.h:450
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:354
ccf::ByteVector SerialisedEntry
Definition serialised_entry.h:8
Definition app_interface.h:19
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:48
SecurityDomain
Definition kv_types.h:255
@ PRIVATE
Definition kv_types.h:257
@ PUBLIC
Definition kv_types.h:256
EntryType
Definition kv_types.h:269
uint64_t Version
Definition version.h:8
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:106
void skip(const uint8_t *&data, size_t &size, size_t skip)
Definition serialized.h:166
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
Definition kv_types.h:52
Version version
Definition kv_types.h:54