CCF
Loading...
Searching...
No Matches
channels.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
7#include "ccf/crypto/hkdf.h"
10#include "ccf/ds/hex.h"
11#include "ccf/entity_id.h"
12#include "ccf/pal/locking.h"
13#include "crypto/key_exchange.h"
14#include "ds/internal_logger.h"
15#include "ds/serialized.h"
16#include "ds/state_machine.h"
17#include "node/node_types.h"
18
19#include <iostream>
20#include <map>
21#include <openssl/crypto.h>
22
23// -Wpedantic flags token pasting of __VA_ARGS__
24#pragma clang diagnostic push
25#pragma clang diagnostic ignored "-Wgnu-zero-variadic-macro-arguments"
26
27#define CHANNEL_RECV_TRACE(s, ...) \
28 LOG_TRACE_FMT("<- {} ({}): " s, peer_id, status.value(), ##__VA_ARGS__)
29#define CHANNEL_SEND_TRACE(s, ...) \
30 LOG_TRACE_FMT("-> {} ({}): " s, peer_id, status.value(), ##__VA_ARGS__)
31
32#define CHANNEL_RECV_FAIL(s, ...) \
33 LOG_FAIL_FMT("<- {} ({}): " s, peer_id, status.value(), ##__VA_ARGS__)
34#define CHANNEL_SEND_FAIL(s, ...) \
35 LOG_FAIL_FMT("-> {} ({}): " s, peer_id, status.value(), ##__VA_ARGS__)
36
37namespace ccf
38{
46}
47
48FMT_BEGIN_NAMESPACE
49template <>
50struct formatter<ccf::ChannelStatus>
51{
52 template <typename ParseContext>
53 constexpr auto parse(ParseContext& ctx)
54 {
55 return ctx.begin();
56 }
57
58 template <typename FormatContext>
59 auto format(const ccf::ChannelStatus& cs, FormatContext& ctx) const
60 {
61 char const* s = "Unknown";
62 switch (cs)
63 {
64 case (ccf::INACTIVE):
65 {
66 s = "INACTIVE";
67 break;
68 }
69 case (ccf::INITIATED):
70 {
71 s = "INITIATED";
72 break;
73 }
75 {
76 s = "WAITING_FOR_FINAL";
77 break;
78 }
79 case (ccf::ESTABLISHED):
80 {
81 s = "ESTABLISHED";
82 break;
83 }
84 }
85
86 return format_to(ctx.out(), "{}", s);
87 }
88};
89FMT_END_NAMESPACE
90
91namespace ccf
92{
93 using MsgNonce = uint64_t;
95
96 // Receive nonces were previously stored per-thread. For backwards
97 // compatibility (live communication with nodes still using this format), we
98 // maintain this serialization struct, but with thread ID (tid) always set to
99 // 0
101 {
102 const uint8_t tid = 0;
103 uint64_t nonce : (sizeof(MsgNonce) - sizeof(tid)) * CHAR_BIT;
104
105 WireNonce(uint64_t nonce_) : nonce(nonce_) {}
106
107 [[nodiscard]] uint64_t get_val() const
108 {
109 return *reinterpret_cast<const uint64_t*>(this);
110 }
111 };
112 static_assert(
113 sizeof(WireNonce) == sizeof(MsgNonce), "WireNonce is the wrong size");
114
115 // Static helper functions for serialization/deserialization
116 inline WireNonce get_wire_nonce(const GcmHdr& header)
117 {
118 return *reinterpret_cast<const WireNonce*>(header.iv.data());
119 }
120
121 template <typename T>
122 inline void append_value(std::vector<uint8_t>& target, const T& t)
123 {
124 const auto size_before = target.size();
125 auto size = sizeof(t);
126 target.resize(size_before + size);
127 auto* data = target.data() + size_before;
128 serialized::write(data, size, t);
129 }
130
131 inline void append_buffer(
132 std::vector<uint8_t>& target, std::span<const uint8_t> src)
133 {
134 const auto size_before = target.size();
135 auto size = src.size() + sizeof(src.size());
136 target.resize(size_before + size);
137 auto* data = target.data() + size_before;
138 serialized::write(data, size, src.size());
139 serialized::write(data, size, src.data(), src.size());
140 }
141
142 // Key exchange states are:
143 // - Have nothing
144 // - Initiated (have my own share)
145 // - Have their share and my share (received init, or received response)
146 // - => Have shared secret
147 // - Know that THEY have shared secret (received response or final)
148 // As soon as we have both shares, we update our send key
149 // As soon as we know that they have shared secret, we update our recv key
150 // Note this assumes that the key exchange messages are reliably delivered,
151 // else we switch keys without telling the peer that we did.
152
154 {
155 public:
156 static std::chrono::system_clock::duration&
158 {
159 static std::chrono::system_clock::duration value =
160 std::chrono::seconds(2);
161 return value;
162 }
163
164 private:
165 struct OutgoingMsg
166 {
167 NodeMsgType type;
168 std::vector<uint8_t> raw_aad; // To be integrity-protected
169 std::vector<uint8_t> raw_plain; // To be encrypted
170
171 OutgoingMsg(
172 NodeMsgType msg_type,
173 std::span<const uint8_t> raw_aad_,
174 std::span<const uint8_t> raw_plain_) :
175 type(msg_type),
176 raw_aad(raw_aad_.begin(), raw_aad_.end()),
177 raw_plain(raw_plain_.begin(), raw_plain_.end())
178 {}
179 };
180
181 ccf::pal::Mutex lock;
182
183 NodeId self;
184 const ccf::crypto::Pem& service_cert;
186 const ccf::crypto::Pem& node_cert;
188 ccf::crypto::Pem peer_cert;
189
190 ringbuffer::WriterPtr to_host;
191 NodeId peer_id;
192
193 // Used for key exchange
196 std::chrono::system_clock::time_point last_initiation_time;
197 static constexpr size_t salt_len = 32;
198 static constexpr size_t shared_key_size = 32;
199 std::vector<uint8_t> hkdf_salt;
200 size_t message_limit;
201
202 // Used for AES GCM authentication/encryption
203 std::unique_ptr<ccf::crypto::KeyAesGcm> recv_key = nullptr;
204 std::unique_ptr<ccf::crypto::KeyAesGcm> send_key = nullptr;
205
206 // Incremented for each tagged/encrypted message
207 std::atomic<MsgNonce> send_nonce{1};
208
209 // Used to buffer at most one message sent on the channel before it is
210 // established
211 std::optional<OutgoingMsg> outgoing_consensus_msg;
212
213 // Used to buffer a small number of messages sent on the channel before it
214 // is established. If this queue fills, then additional send attempts while
215 // the channel is still being established will not be buffered, and the
216 // caller should react appropriately.
217 static constexpr size_t outgoing_forwarding_queue_size = 10;
218 std::vector<OutgoingMsg> outgoing_forwarding_msgs;
219
220 // Used to prevent replayed messages.
221 // Set to the latest successfully received nonce.
222 MsgNonce local_recv_nonce = {0};
223
224 void check_message_limit()
225 {
226 // At half message limit, trigger a new key exchange.
227 // At hard message limit, drop existing keys, ensuring no further
228 // communication until fresh keys have been exchanged
229 const auto lower_limit = message_limit / 2;
230 size_t num_messages = send_nonce + local_recv_nonce;
231 if (num_messages >= lower_limit && status.check(ESTABLISHED))
232 {
234 "Reached message limit ({}+{} >= {}), triggering new key exchange",
235 send_nonce,
236 local_recv_nonce,
237 lower_limit);
238 reset_key_exchange();
239 initiate();
240 }
241 else if (num_messages >= message_limit)
242 {
244 "Reached hard message limit ({}+{} >= {}), dropping previous keys",
245 send_nonce,
246 local_recv_nonce,
247 message_limit);
248
249 send_key = nullptr;
250 send_nonce = 0;
251 recv_key = nullptr;
252 local_recv_nonce = 0;
253 reset_key_exchange();
254 initiate();
255 }
256 }
257
258 bool decrypt(
259 const GcmHdr& header,
260 std::span<const uint8_t> aad,
261 std::span<const uint8_t> cipher,
262 std::vector<uint8_t>& plain)
263 {
264 if (recv_key == nullptr)
265 {
266 throw std::logic_error("Tried to decrypt, but have no receive key");
267 }
268
269 auto wire_nonce = get_wire_nonce(header);
270 auto recv_nonce = wire_nonce.nonce;
271
273 "decrypt({} bytes, {} bytes) (nonce={})",
274 aad.size(),
275 cipher.size(),
276 recv_nonce);
277
278 // Note: We must assume that some messages are dropped, i.e. we may not
279 // see every nonce/sequence number, but they must be increasing.
280
281 if (recv_nonce <= local_recv_nonce)
282 {
283 // If the nonce received has already been processed, return
284 // See https://github.com/microsoft/CCF/issues/2492 for more details on
285 // how this can happen around election time
287 "Received past nonce, received:{}, "
288 "last_seen:{}",
289 recv_nonce,
290 local_recv_nonce);
291 return false;
292 }
293
294 auto ret =
295 recv_key->decrypt(header.get_iv(), header.tag, cipher, aad, plain);
296 if (ret)
297 {
298 // Set local recv nonce to received nonce only if verification is
299 // successful
300 local_recv_nonce = recv_nonce;
301 }
302
303 check_message_limit();
304
305 return ret;
306 }
307
308 bool verify(const GcmHdr& header, std::span<const uint8_t> aad)
309 {
310 std::vector<uint8_t> empty_plaintext;
311 return decrypt(header, aad, {}, empty_plaintext);
312 }
313
314 void send_key_exchange_init()
315 {
316 std::vector<uint8_t> payload;
317 {
320 append_buffer(payload, kex_ctx.get_own_key_share());
321 auto signature = node_kp->sign(kex_ctx.get_own_key_share());
322 append_buffer(payload, signature);
324 payload,
325 std::span<const uint8_t>(node_cert.data(), node_cert.size()));
326 append_buffer(payload, hkdf_salt);
327 }
328
330 "send_key_exchange_init: node serial: {}",
331 make_verifier(node_cert)->serial_number());
332
334 node_outbound,
335 to_host,
336 peer_id.value(),
338 self.value(),
339 payload);
340 }
341
342 void send_key_exchange_response()
343 {
344 std::vector<uint8_t> signature;
345 {
346 auto to_sign = kex_ctx.get_own_key_share();
347 const auto& peer_ks = kex_ctx.get_peer_key_share();
348 to_sign.insert(to_sign.end(), peer_ks.begin(), peer_ks.end());
349 signature = node_kp->sign(to_sign);
350 }
351
352 std::vector<uint8_t> payload;
353 {
356 append_buffer(payload, kex_ctx.get_own_key_share());
357 append_buffer(payload, signature);
359 payload,
360 std::span<const uint8_t>(node_cert.data(), node_cert.size()));
361 }
362
364 "send_key_exchange_response: oks={}, serialised_signed_share={}",
365 ds::to_hex(kex_ctx.get_own_key_share()),
366 ds::to_hex(payload));
367
369 node_outbound,
370 to_host,
371 peer_id.value(),
373 self.value(),
374 payload);
375 }
376
377 void send_key_exchange_final()
378 {
379 std::vector<uint8_t> payload;
380 {
382 // append_value(payload, protocol_version); // Not sent by
383 // current protocol!
384 auto signature = node_kp->sign(kex_ctx.get_peer_key_share());
385 append_buffer(payload, signature);
386 }
387
389 "key_exchange_final: ks={}, serialised_signed_key_share={}",
390 ds::to_hex(kex_ctx.get_peer_key_share()),
391 ds::to_hex(payload));
392
394 node_outbound,
395 to_host,
396 peer_id.value(),
398 self.value(),
399 payload);
400 }
401
402 void advance_connection_attempt()
403 {
404 if (status.check(INACTIVE))
405 {
406 // We have no key and believe no key exchange is in process - start a
407 // new iteration of the key exchange protocol
408 initiate();
409 }
410 else if (status.check(INITIATED))
411 {
412 const auto time_since_initiated =
413 decltype(last_initiation_time)::clock::now() - last_initiation_time;
414 if (time_since_initiated >= min_gap_between_initiation_attempts())
415 {
416 // If this node attempts to initiate too early when the peer node
417 // starts up, they will never receive the init message (they drop it
418 // if it arrives too early in their state machine). The same state
419 // could also occur later, if the initiate message is lost in transit.
420 // So sometimes this node needs to re-initiate. However, if this node
421 // sends too fast before the channel is established, and each send
422 // generates a new handshake, it may constantly generate new handshake
423 // attempts and never succeed. Additionally, when talking to peers
424 // using the old channel behaviour, this node should try to avoid
425 // confusing them by sending multiple adjacent initiate requests -
426 // they will only process the first one they receive. To avoid these
427 // problems with initiation spam, we have a minimum delay between
428 // initiation attempts. This should be low enough to get reasonable
429 // liveness (re-attempt connections in the presence of dropped
430 // messages), but high enough to give successful roundtrips a chance
431 // to complete.
432 initiate();
433 }
434 }
435 }
436
437 bool recv_key_exchange_init(
438 const uint8_t* data, size_t size, bool they_have_priority = false)
439 {
441 "recv_key_exchange_init({} bytes, {})", size, they_have_priority);
442
443 // Parse fields from incoming message
444 auto peer_version = serialized::read<size_t>(data, size);
445 if (peer_version != protocol_version)
446 {
448 "Protocol version mismatch (node={}, peer={})",
450 peer_version);
451 return false;
452 }
453
454 auto ks = extract_span(data, size);
455 if (ks.empty())
456 {
457 CHANNEL_RECV_FAIL("Empty keyshare");
458 return false;
459 }
460
461 auto sig = extract_span(data, size);
462 if (sig.empty())
463 {
464 CHANNEL_RECV_FAIL("Empty signature");
465 return false;
466 }
467
468 auto pc = extract_span(data, size);
469 if (pc.empty())
470 {
471 CHANNEL_RECV_FAIL("Empty cert");
472 return false;
473 }
474
475 auto salt = extract_span(data, size);
476 if (salt.empty())
477 {
478 CHANNEL_RECV_FAIL("Empty salt");
479 return false;
480 }
481
482 if (size != 0)
483 {
484 CHANNEL_RECV_FAIL("{} exccess bytes remaining", size);
485 return false;
486 }
487
488 // Validate cert and signature in message
489 ccf::crypto::Pem cert;
491 if (!verify_peer_certificate(pc, cert, verifier))
492 {
494 "Peer certificate verification failed - recv_key_exchange_init "
495 "failed to verify peer cert:\n{}\nUsing trusted service "
496 "certificate:\n{}",
497 cert.str(),
498 service_cert.str());
499 return false;
500 }
501
502 if (!verify_peer_signature(ks, sig, verifier))
503 {
504 return false;
505 }
506
507 // Both nodes tried to initiate the channel, the one with priority
508 // wins.
509 if (status.check(INITIATED) && !they_have_priority)
510 {
511 CHANNEL_RECV_TRACE("Ignoring lower priority key init");
512 return true;
513 }
514
515 // Whatever else we _were_ doing, we've received a valid init from them
516 // - reset to use it
517 if (status.check(ESTABLISHED))
518 {
519 kex_ctx.reset();
520 }
521 peer_cert = cert;
522 peer_cv = verifier;
523
525 "recv_key_exchange_init: version={} ks={} sig={} pc={} salt={}",
526 peer_version,
527 ds::to_hex(ks),
528 ds::to_hex(sig),
529 ds::to_hex(pc),
530 ds::to_hex(salt));
531
532 hkdf_salt = {salt.data(), salt.data() + salt.size()};
533
534 kex_ctx.load_peer_key_share(ks);
535
536 update_send_key();
537
539
540 // We are the responder and we return a signature over both public key
541 // shares back to the initiator
542 send_key_exchange_response();
543
544 flush_pending_outgoing();
545
546 return true;
547 }
548
549 bool recv_key_exchange_response(const uint8_t* data, size_t size)
550 {
551 CHANNEL_RECV_TRACE("recv_key_exchange_response({} bytes)", size);
552
553 if (status.value() != INITIATED)
554 {
555 CHANNEL_RECV_FAIL("Ignoring key exchange response - not expecting it");
556 return false;
557 }
558
559 // Parse fields from incoming message
560 auto peer_version = serialized::read<size_t>(data, size);
561 if (peer_version != protocol_version)
562 {
564 "Protocol version mismatch (node={}, peer={})",
566 peer_version);
567 return false;
568 }
569
570 auto ks = extract_span(data, size);
571 if (ks.empty())
572 {
573 CHANNEL_RECV_FAIL("Empty keyshare");
574 return false;
575 }
576
577 auto sig = extract_span(data, size);
578 if (sig.empty())
579 {
580 CHANNEL_RECV_FAIL("Empty signature");
581 return false;
582 }
583
584 auto pc = extract_span(data, size);
585 if (pc.empty())
586 {
587 CHANNEL_RECV_FAIL("Empty cert");
588 return false;
589 }
590
591 if (size != 0)
592 {
593 CHANNEL_RECV_FAIL("{} exccess bytes remaining", size);
594 return false;
595 }
596
597 // Validate cert and signature in message
598 ccf::crypto::Pem cert;
600 if (!verify_peer_certificate(pc, cert, verifier))
601 {
603 "Peer certificate verification failed - recv_key_exchange_response "
604 "failed to verify peer cert:\n{}\nUsing trusted service "
605 "certificate:\n{}",
606 cert.str(),
607 service_cert.str());
608 return false;
609 }
610
611 {
612 // We are the initiator and expect a signature over both key shares
613 std::vector<uint8_t> signed_msg(ks.begin(), ks.end());
614 const auto& oks = kex_ctx.get_own_key_share();
615 signed_msg.insert(signed_msg.end(), oks.begin(), oks.end());
616
617 if (!verify_peer_signature(signed_msg, sig, verifier))
618 {
619 // This isn't a valid signature for this key exchange attempt.
621 "Peer certificate verification failed - recv_key_exchange_response "
622 "failed to verify signature from cert:\n{}",
623 cert.str());
624 return false;
625 }
626 }
627
628 peer_cert = cert;
629 peer_cv = verifier;
630
631 kex_ctx.load_peer_key_share(ks);
632
633 update_send_key();
634
635 send_key_exchange_final();
636
637 flush_pending_outgoing();
638
639 update_recv_key();
640
641 establish();
642
643 return true;
644 }
645
646 bool recv_key_exchange_final(const uint8_t* data, size_t size)
647 {
648 CHANNEL_RECV_TRACE("recv_key_exchange_final({} bytes)", size);
649
650 if (status.value() != WAITING_FOR_FINAL)
651 {
652 CHANNEL_RECV_FAIL("Ignoring key exchange final - not expecting it");
653 return false;
654 }
655
656 // Parse fields from incoming message
657 // size_t peer_version = serialized::read<size_t>(data, size);
658 // if (peer_version != protocol_version)
659 // {
660 // CHANNEL_RECV_FAIL(
661 // "Protocol version mismatch (node={}, peer={})",
662 // protocol_version,
663 // peer_version);
664 // return false;
665 // }
666
667 auto sig = extract_span(data, size);
668 if (sig.empty())
669 {
670 CHANNEL_RECV_FAIL("Empty signature");
671 return false;
672 }
673
674 if (!verify_peer_signature(kex_ctx.get_own_key_share(), sig, peer_cv))
675 {
677 "Peer certificate verification failed - recv_key_exchange_final "
678 "failed to verify signature from peer with serial number {}",
679 peer_cv->serial_number());
680 return false;
681 }
682
683 update_recv_key();
684
685 establish();
686
687 return true;
688 }
689
690 std::span<const uint8_t> extract_span(
691 const uint8_t*& data, size_t& size) const
692 {
693 if (size == 0)
694 {
695 return {};
696 }
697
698 auto sz = serialized::read<size_t>(data, size);
699 const uint8_t* data_start = data;
700
701 if (sz > size)
702 {
704 "Buffer header wants {} bytes, but only {} remain", sz, size);
705 return {};
706 }
707
708 data += sz;
709 size -= sz;
710
711 return {data_start, sz};
712 }
713
714 bool verify_peer_certificate(
715 std::span<const uint8_t> pc,
716 ccf::crypto::Pem& cert,
717 ccf::crypto::VerifierPtr& verifier)
718 {
719 if (!pc.empty())
720 {
721 cert = ccf::crypto::Pem(pc);
722 verifier = ccf::crypto::make_verifier(cert);
723
724 // 'true' is `ignore_time` => These node-to-node channels do not care
725 // about certificate times, and should still pass even when given
726 // expired certs
727 if (!verifier->verify_certificate(
728 {&service_cert}, {}, true /* no validity expiration check */))
729 {
730 return false;
731 }
732
734 "New peer certificate: {}\n{}",
735 verifier->serial_number(),
736 cert.str());
737
738 return true;
739 }
740
741 return false;
742 }
743
744 bool verify_peer_signature(
745 std::span<const uint8_t> msg,
746 std::span<const uint8_t> sig,
748 {
750 "Verifying peer signature with peer certificate serial {}",
751 verifier ? verifier->serial_number() : "no peer_cv!");
752
753 return verifier && verifier->verify(msg, sig);
754 }
755
756 void update_send_key()
757 {
758 const std::string label_to = self.value() + peer_id.value();
759 const std::span<const uint8_t> label(
760 reinterpret_cast<const uint8_t*>(label_to.c_str()), label_to.size());
761 const auto key_bytes = ccf::crypto::hkdf(
763 shared_key_size,
764 kex_ctx.get_shared_secret(),
765 hkdf_salt,
766 label);
767 send_key = ccf::crypto::make_key_aes_gcm(key_bytes);
768
769 send_nonce = 1;
770 }
771
772 void update_recv_key()
773 {
774 const std::string label_from = peer_id.value() + self.value();
775 const std::span<const uint8_t> label(
776 reinterpret_cast<const uint8_t*>(label_from.c_str()),
777 label_from.size());
778 const auto key_bytes = ccf::crypto::hkdf(
780 shared_key_size,
781 kex_ctx.get_shared_secret(),
782 hkdf_salt,
783 label);
784 recv_key = ccf::crypto::make_key_aes_gcm(key_bytes);
785
786 local_recv_nonce = 0;
787 }
788
789 void establish()
790 {
791 status.advance(ESTABLISHED);
792 LOG_INFO_FMT("Node channel with {} is now established.", peer_id);
793
794 kex_ctx.reset();
795
796 auto node_cv = make_verifier(node_cert);
798 "Node certificate serial numbers: node={} peer={}",
799 node_cv->serial_number(),
800 peer_cv->serial_number());
801 }
802
803 void flush_pending_outgoing()
804 {
805 if (outgoing_consensus_msg.has_value())
806 {
807 send_unsafe(
808 outgoing_consensus_msg->type,
809 outgoing_consensus_msg->raw_aad,
810 outgoing_consensus_msg->raw_plain);
811 outgoing_consensus_msg.reset();
812 }
813
814 for (auto& outgoing_msg : outgoing_forwarding_msgs)
815 {
816 send_unsafe(
817 outgoing_msg.type, outgoing_msg.raw_aad, outgoing_msg.raw_plain);
818 CHANNEL_SEND_TRACE("Flushing previously queued forwarding message");
819 }
820 outgoing_forwarding_msgs.clear();
821 }
822
823 void initiate()
824 {
825 LOG_INFO_FMT("Initiating node channel with {}.", peer_id);
826
827 // Begin with new key exchange
828 kex_ctx.reset();
829 peer_cert = {};
830 peer_cv.reset();
831
832 auto e = ccf::crypto::get_entropy();
833 hkdf_salt = e->random(salt_len);
834
835 // As a future simplification, we would like this to always be true
836 // (initiations must travel through reset/inactive), but it is not
837 // currently true
838 // status.expect(INACTIVE);
839 status.advance(INITIATED);
840
841 last_initiation_time = decltype(last_initiation_time)::clock::now();
842
843 send_key_exchange_init();
844 }
845
846 void reset_key_exchange()
847 {
848 LOG_INFO_FMT("Resetting channel with {}", peer_id);
849
850 status.advance(INACTIVE);
851 kex_ctx.reset();
852 peer_cert = {};
853 peer_cv.reset();
854
855 auto e = ccf::crypto::get_entropy();
856 hkdf_salt = e->random(salt_len);
857 }
858
859 bool send_unsafe(
860 NodeMsgType type,
861 std::span<const uint8_t> aad,
862 std::span<const uint8_t> plain)
863 {
864 if (send_key == nullptr)
865 {
866 advance_connection_attempt();
867 switch (type)
868 {
870 {
871 if (outgoing_consensus_msg.has_value())
872 {
874 "Dropping outgoing consensus message - replaced by new "
875 "consensus message");
876 }
877 outgoing_consensus_msg = OutgoingMsg(type, aad, plain);
878 return true;
879 }
880
882 {
883 if (
884 outgoing_forwarding_msgs.size() < outgoing_forwarding_queue_size)
885 {
886 outgoing_forwarding_msgs.emplace_back(type, aad, plain);
888 "Queueing outgoing forwarding message - the is the {}/{} "
889 "buffered message",
890 outgoing_forwarding_msgs.size(),
891 outgoing_forwarding_queue_size);
892 return true;
893 }
894
896 "Unable to queue outgoing forwarding message - already queued "
897 "maximum {} messages",
898 outgoing_forwarding_queue_size);
899 return false;
900 }
901
903 {
905 "Cannot send channel message on unestablished channel");
906 return false;
907 }
908
909 default:
910 {
912 "Cannot send message of unexpected type {} on unestablished "
913 "channel",
914 static_cast<size_t>(type));
915 return false;
916 }
917 }
918 }
919
920 auto nonce = send_nonce.fetch_add(1);
921 WireNonce wire_nonce(nonce);
922
924 "send({}, {} bytes, {} bytes) (nonce={})",
925 (size_t)type,
926 aad.size(),
927 plain.size(),
928 nonce);
929
930 GcmHdr gcm_hdr;
931 gcm_hdr.set_iv(
932 reinterpret_cast<const uint8_t*>(&wire_nonce), sizeof(wire_nonce));
933
934 std::vector<uint8_t> cipher;
935 assert(send_key);
936 send_key->encrypt(gcm_hdr.get_iv(), plain, aad, cipher, gcm_hdr.tag);
937
938 const auto gcm_hdr_serialised = gcm_hdr.serialise();
939
940 // Payload is concatenation of 3 things:
941 // 1) aad
942 // 2) gcm header
943 // 3) ciphertext
944 // NB: None of these are length-prefixed, so it is assumed that the
945 // receiver knows the fixed size of the aad and gcm header
946 const serializer::ByteRange payload[] = {
947 {aad.data(), static_cast<size_t>(aad.size())},
948 {gcm_hdr_serialised.data(),
949 static_cast<size_t>(gcm_hdr_serialised.size())},
950 {cipher.data(), static_cast<size_t>(cipher.size())}};
951
953 node_outbound, to_host, peer_id.value(), type, self.value(), payload);
954
955 check_message_limit();
956
957 return true;
958 }
959
960 public:
961 static constexpr size_t protocol_version = 1;
962
964 ringbuffer::AbstractWriterFactory& writer_factory,
965 const ccf::crypto::Pem& service_cert_,
967 const ccf::crypto::Pem& node_cert_,
968 NodeId self_,
969 NodeId peer_id_,
970 size_t message_limit_) :
971 self(std::move(self_)),
972 service_cert(service_cert_),
973 node_kp(std::move(node_kp_)),
974 node_cert(node_cert_),
975 to_host(writer_factory.create_writer_to_outside()),
976 peer_id(std::move(peer_id_)),
977 status(fmt::format("Channel to {}", peer_id), INACTIVE),
978 message_limit(message_limit_)
979 {
980 auto e = ccf::crypto::get_entropy();
981 hkdf_salt = e->random(salt_len);
982 }
983
985 {
986 std::lock_guard<ccf::pal::Mutex> guard(lock);
987 return recv_key != nullptr && send_key != nullptr;
988 }
989
990 // Protocol overview:
991 //
992 // initiate()
993 // > key_exchange_init message
994 // recv_key_exchange_init() [by responder]
995 // < key_exchange_response message
996 // recv_key_exchange_response() [by initiator]
997 // > key_exchange_final message
998 // recv_key_exchange_final() [by responder]
999 // both reach status == ESTABLISHED
1000
1001 bool send(
1002 NodeMsgType type,
1003 std::span<const uint8_t> aad,
1004 std::span<const uint8_t> plain = {})
1005 {
1006 std::lock_guard<ccf::pal::Mutex> guard(lock);
1007
1008 return send_unsafe(type, aad, plain);
1009 }
1010
1012 std::span<const uint8_t> aad, const uint8_t*& data, size_t& size)
1013 {
1014 std::lock_guard<ccf::pal::Mutex> guard(lock);
1015
1016 // Receive authenticated message, modifying data to point to the start of
1017 // the non-authenticated plaintext payload
1018 if (recv_key == nullptr)
1019 {
1021 "Node channel with {} cannot receive authenticated message: not "
1022 "established a receive key, status={}",
1023 peer_id,
1024 status.value());
1025 advance_connection_attempt();
1026 return false;
1027 }
1028
1029 GcmHdr hdr;
1030 hdr.deserialise(data, size);
1031
1032 if (!verify(hdr, aad))
1033 {
1034 CHANNEL_RECV_FAIL("Failed to verify node");
1035 return false;
1036 }
1037
1038 return true;
1039 }
1040
1041 bool recv_authenticated_with_load(const uint8_t*& data, size_t& size)
1042 {
1043 std::lock_guard<ccf::pal::Mutex> guard(lock);
1044
1045 // Receive authenticated message, modifying data to point to the start of
1046 // the non-authenticated plaintext payload. data contains payload first,
1047 // then GCM header
1048
1049 if (recv_key == nullptr)
1050 {
1052 "Node channel with {} cannot receive authenticated message with "
1053 "payload: not established a receive key, status={}",
1054 peer_id,
1055 status.value());
1056 advance_connection_attempt();
1057 return false;
1058 }
1059
1060 const uint8_t* data_ = data;
1061 size_t size_ = size;
1062
1063 GcmHdr hdr;
1064 serialized::skip(data_, size_, (size_ - GcmHdr::serialised_size()));
1065 hdr.deserialise(data_, size_);
1066 size -= GcmHdr::serialised_size();
1067
1068 if (!verify(hdr, std::span<const uint8_t>(data, size)))
1069 {
1070 CHANNEL_RECV_FAIL("Failed to verify node message with payload");
1071 return false;
1072 }
1073
1074 return true;
1075 }
1076
1077 std::optional<std::vector<uint8_t>> recv_encrypted(
1078 std::span<const uint8_t> aad, const uint8_t*& data, size_t& size)
1079 {
1080 std::lock_guard<ccf::pal::Mutex> guard(lock);
1081
1082 // Receive encrypted message, returning the decrypted payload
1083 if (recv_key == nullptr)
1084 {
1086 "Node channel with {} cannot receive encrypted message: not "
1087 "established a receive key, status={}",
1088 peer_id,
1089 status.value());
1090 advance_connection_attempt();
1091 return std::nullopt;
1092 }
1093
1094 GcmHdr hdr;
1095 hdr.deserialise(data, size);
1096
1097 std::vector<uint8_t> plain;
1098 if (!decrypt(hdr, aad, std::span<const uint8_t>(data, size), plain))
1099 {
1100 CHANNEL_RECV_FAIL("Failed to decrypt node message");
1101 return std::nullopt;
1102 }
1103
1104 return plain;
1105 }
1106
1108 {
1109 std::lock_guard<ccf::pal::Mutex> guard(lock);
1110
1111 RINGBUFFER_WRITE_MESSAGE(close_node_outbound, to_host, peer_id.value());
1112 reset_key_exchange();
1113 outgoing_consensus_msg.reset();
1114
1115 recv_key.reset();
1116 send_key.reset();
1117 }
1118
1119 bool recv_key_exchange_message(const uint8_t* data, size_t size)
1120 {
1121 std::lock_guard<ccf::pal::Mutex> guard(lock);
1122
1123 try
1124 {
1125 auto chmsg = serialized::read<ChannelMsg>(data, size);
1126 switch (chmsg)
1127 {
1128 case key_exchange_init:
1129 {
1130 // In the case of concurrent key_exchange_init's from both nodes,
1131 // the one with the lower ID wins.
1132 return recv_key_exchange_init(data, size, self < peer_id);
1133 }
1134
1136 {
1137 return recv_key_exchange_response(data, size);
1138 }
1139
1140 case key_exchange_final:
1141 {
1142 return recv_key_exchange_final(data, size);
1143 }
1144
1145 default:
1146 {
1147 throw std::runtime_error(fmt::format(
1148 "Received message with initial bytes {} from {} - not recognised "
1149 "as a key exchange message",
1150 chmsg,
1151 peer_id));
1152 }
1153 }
1154 }
1155 catch (const std::exception& e)
1156 {
1157 LOG_FAIL_FMT("Exception in {}", __PRETTY_FUNCTION__);
1158 LOG_DEBUG_FMT("Error: {}", e.what());
1159 return false;
1160 }
1161 }
1162 };
1163}
1164
1165#undef CHANNEL_RECV_TRACE
1166#undef CHANNEL_SEND_TRACE
1167#undef CHANNEL_RECV_FAIL
1168
1169#pragma clang diagnostic pop
#define CHANNEL_SEND_TRACE(s,...)
Definition channels.h:29
#define CHANNEL_RECV_TRACE(s,...)
Definition channels.h:27
#define CHANNEL_SEND_FAIL(s,...)
Definition channels.h:34
#define CHANNEL_RECV_FAIL(s,...)
Definition channels.h:32
Definition channels.h:154
std::optional< std::vector< uint8_t > > recv_encrypted(std::span< const uint8_t > aad, const uint8_t *&data, size_t &size)
Definition channels.h:1077
static std::chrono::system_clock::duration & min_gap_between_initiation_attempts()
Definition channels.h:157
bool channel_open()
Definition channels.h:984
bool recv_authenticated(std::span< const uint8_t > aad, const uint8_t *&data, size_t &size)
Definition channels.h:1011
bool recv_authenticated_with_load(const uint8_t *&data, size_t &size)
Definition channels.h:1041
bool recv_key_exchange_message(const uint8_t *data, size_t size)
Definition channels.h:1119
bool send(NodeMsgType type, std::span< const uint8_t > aad, std::span< const uint8_t > plain={})
Definition channels.h:1001
void close_channel()
Definition channels.h:1107
Channel(ringbuffer::AbstractWriterFactory &writer_factory, const ccf::crypto::Pem &service_cert_, ccf::crypto::ECKeyPairPtr node_kp_, const ccf::crypto::Pem &node_cert_, NodeId self_, NodeId peer_id_, size_t message_limit_)
Definition channels.h:963
static constexpr size_t protocol_version
Definition channels.h:961
Definition pem.h:18
size_t size() const
Definition pem.h:61
const std::string & str() const
Definition pem.h:46
uint8_t * data()
Definition pem.h:51
Definition state_machine.h:15
T value() const
Definition state_machine.h:40
void advance(T state_)
Definition state_machine.h:45
bool check(T state_) const
Definition state_machine.h:35
Definition ring_buffer_types.h:157
Definition key_exchange.h:20
std::vector< uint8_t > get_peer_key_share() const
Definition key_exchange.h:64
void load_peer_key_share(std::span< const uint8_t > ks)
Definition key_exchange.h:84
const std::vector< uint8_t > & get_shared_secret()
Definition key_exchange.h:106
std::vector< uint8_t > get_own_key_share()
Definition key_exchange.h:48
void reset()
Definition key_exchange.h:76
#define LOG_INFO_FMT
Definition internal_logger.h:15
#define LOG_DEBUG_FMT
Definition internal_logger.h:14
#define LOG_FAIL_FMT
Definition internal_logger.h:16
std::unique_ptr< KeyAesGcm > make_key_aes_gcm(std::span< const uint8_t > rawKey)
Free function implementation.
Definition symmetric_key.cpp:100
std::vector< uint8_t > hkdf(MDType md_type, size_t length, const std::span< const uint8_t > &ikm, const std::span< const uint8_t > &salt={}, const std::span< const uint8_t > &info={})
Definition hash.cpp:51
EntropyPtr get_entropy()
Definition entropy.cpp:10
std::shared_ptr< Verifier > VerifierPtr
Definition verifier.h:168
VerifierPtr make_verifier(const std::vector< uint8_t > &cert)
Definition verifier.cpp:18
std::shared_ptr< ECKeyPair > ECKeyPairPtr
Definition ec_key_pair.h:144
std::mutex Mutex
Definition locking.h:12
Definition app_interface.h:13
EntityId< NodeIdFormatter > NodeId
Definition entity_id.h:164
ChannelStatus
Definition channels.h:40
@ WAITING_FOR_FINAL
Definition channels.h:43
@ ESTABLISHED
Definition channels.h:44
@ INITIATED
Definition channels.h:42
@ INACTIVE
Definition channels.h:41
uint64_t MsgNonce
Definition channels.h:93
@ key_exchange_init
Definition node_types.h:33
@ key_exchange_final
Definition node_types.h:35
@ key_exchange_response
Definition node_types.h:34
void append_buffer(std::vector< uint8_t > &target, std::span< const uint8_t > src)
Definition channels.h:131
WireNonce get_wire_nonce(const GcmHdr &header)
Definition channels.h:116
ccf::crypto::FixedSizeGcmHeader< sizeof(MsgNonce)> GcmHdr
Definition channels.h:94
void append_value(std::vector< uint8_t > &target, const T &t)
Definition channels.h:122
NodeMsgType
Definition node_types.h:21
@ channel_msg
Definition node_types.h:22
@ consensus_msg
Definition node_types.h:23
@ forwarded_msg
Definition node_types.h:24
std::shared_ptr< AbstractWriter > WriterPtr
Definition ring_buffer_types.h:154
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.
#define RINGBUFFER_WRITE_MESSAGE(MSG,...)
Definition ring_buffer_types.h:259
Definition channels.h:101
uint64_t nonce
Definition channels.h:103
WireNonce(uint64_t nonce_)
Definition channels.h:105
uint64_t get_val() const
Definition channels.h:107
const uint8_t tid
Definition channels.h:102
Definition symmetric_key.h:37
static size_t serialised_size()
Definition symmetric_key.h:42
std::vector< uint8_t > iv
Definition symmetric_key.h:21
void deserialise(const std::vector< uint8_t > &ser)
Definition symmetric_key.cpp:54
constexpr auto parse(ParseContext &ctx)
Definition channels.h:53
auto format(const ccf::ChannelStatus &cs, FormatContext &ctx) const
Definition channels.h:59
Definition serializer.h:27
const uint8_t * data
Definition serializer.h:28