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