sizeof(header2) - sizeof(header2.header_crc));
}
- auto message = MessageHeaderFrame::Encode(header2,
- m->get_payload().length(),
- m->get_middle().length(),
- m->get_data().length());
- if (auth_meta->is_mode_secure()) {
- ceph_assert(session_stream_handlers.tx);
-
- // let's cipher allocate one huge buffer for entire ciphertext.
- // NOTE: ultimately we'll align these sizes to cipher's block size.
- // AES-GCM can live without that as it's basically stream cipher.
- session_stream_handlers.tx->reset_tx_handler({
- message.get_buffer().length(),
- m->get_payload().length(),
- m->get_middle().length(),
- m->get_data().length()
- });
-
- ceph_assert(message.get_buffer().length());
- session_stream_handlers.tx->authenticated_encrypt_update(
- std::move(message.get_buffer()));
-
- // receiver uses "front" for "payload"
- // TODO: switch TxHandler from `bl&&` to `const bl&`.
- if (m->get_payload().length()) {
- session_stream_handlers.tx->authenticated_encrypt_update(
- m->get_payload());
- }
- if (m->get_middle().length()) {
- session_stream_handlers.tx->authenticated_encrypt_update(
- m->get_middle());
- }
- if (m->get_data().length()) {
- session_stream_handlers.tx->authenticated_encrypt_update(
- m->get_data());
- }
-
- auto cipherbl = session_stream_handlers.tx->authenticated_encrypt_final();
- connection->outcoming_bl.claim_append(cipherbl);
- } else {
- connection->outcoming_bl.claim_append(message.get_buffer());
- connection->outcoming_bl.append(m->get_payload());
- connection->outcoming_bl.append(m->get_middle());
- connection->outcoming_bl.append(m->get_data());
- }
+ auto message = MessageHeaderFrame::Encode(session_stream_handlers,
+ header2,
+ m->get_payload(),
+ m->get_middle(),
+ m->get_data());
+ connection->outcoming_bl.claim_append(message.get_buffer());
ldout(cct, 5) << __func__ << " sending message m=" << m
<< " seq=" << m->get_seq() << " " << *m << dendl;
if (rx_segments_desc.size() == rx_segments_data.size()) {
// OK, all segments planned to read are read. Can go with epilogue.
- if (session_stream_handlers.rx) {
- return READ(FRAME_EPILOGUE_SIZE, handle_read_frame_epilogue_main);
- } else {
- return handle_read_frame_dispatch();
- }
+ return READ(FRAME_EPILOGUE_SIZE, handle_read_frame_epilogue_main);
} else {
// TODO: for makeshift only. This will be more generic and throttled
return read_frame_segment();
}
state = READ_MESSAGE_COMPLETE;
- // TODO: implement epilogue for non-secure frames
- if (session_stream_handlers.rx) {
- return READ(FRAME_EPILOGUE_SIZE, handle_read_frame_epilogue_main);
- } else {
- return handle_read_frame_dispatch();
- }
+ return READ(FRAME_EPILOGUE_SIZE, handle_read_frame_epilogue_main);
}
-CtPtr ProtocolV2::handle_read_frame_epilogue_main(char *buffer, int r) {
+CtPtr ProtocolV2::handle_read_frame_epilogue_main(char *buffer, int r)
+{
ldout(cct, 20) << __func__ << " r=" << r << dendl;
if (r < 0) {
return _fault();
}
- // I expect that ::temp_buffer is being used here.
- ceph::bufferlist epilogue;
- epilogue.push_back(buffer::create_static(FRAME_EPILOGUE_SIZE, buffer));
-
+ auto& epilogue = reinterpret_cast<epilogue_block_t&>(*buffer);
// FIXME: if (auth_meta->is_mode_secure()) {
if (session_stream_handlers.rx) {
ceph_assert(session_stream_handlers.rx);
ceph_assert(FRAME_EPILOGUE_SIZE == \
session_stream_handlers.rx->get_extra_size_at_final());
+
+ // I expect that ::temp_buffer is being used here.
+ ceph::bufferlist epilogue_bl;
+ epilogue_bl.push_back(buffer::create_static(FRAME_EPILOGUE_SIZE,
+ epilogue.auth_tag));
try {
session_stream_handlers.rx->authenticated_decrypt_update_final(
- std::move(epilogue), segment_t::DEFAULT_ALIGNMENT);
+ std::move(epilogue_bl), segment_t::DEFAULT_ALIGNMENT);
} catch (ceph::crypto::onwire::MsgAuthError &e) {
ldout(cct, 5) << __func__ << " message authentication failed: "
<< e.what() << dendl;
return _fault();
}
+ } else {
+ for (std::uint8_t idx = 0; idx < rx_segments_data.size(); idx++) {
+ const __u32 expected_crc = epilogue.crc_values[idx];
+ const __u32 calculated_crc = rx_segments_data[idx].crc32c(-1);
+ if (expected_crc != calculated_crc) {
+ ldout(cct, 5) << __func__ << " message integrity check failed: "
+ << " expected_crc=" << expected_crc
+ << " calculated_crc=" << calculated_crc
+ << dendl;
+ return _fault();
+ } else {
+ ldout(cct, 20) << __func__ << " message integrity check success: "
+ << " expected_crc=" << expected_crc
+ << " calculated_crc=" << calculated_crc
+ << dendl;
+ }
+ }
}
return handle_read_frame_dispatch();
public:
- struct onwire_segment_t {
- // crypto-processed segment can be expanded on-wire because of:
- // * padding to achieve CRYPTO_BLOCK_SIZE alignment,
- // * authentication tag. It's appended at the end of message.
- // See RxHandler::get_extra_size_at_final().
- __le32 onwire_length;
-
- struct ceph::msgr::v2::segment_t logical;
- } __attribute__((packed));
-
- struct SegmentIndex {
- struct Msg {
- static constexpr std::size_t HEADER = 0;
- static constexpr std::size_t FRONT = 1;
- static constexpr std::size_t MIDDLE = 2;
- static constexpr std::size_t DATA = 3;
- };
-
- struct Frame {
- static constexpr std::size_t PAYLOAD = 0;
- };
- };
-
- boost::container::static_vector<onwire_segment_t,
+ boost::container::static_vector<ceph::msgr::v2::onwire_segment_t,
ceph::msgr::v2::MAX_NUM_SEGMENTS> rx_segments_desc;
boost::container::static_vector<ceph::bufferlist,
ceph::msgr::v2::MAX_NUM_SEGMENTS> rx_segments_data;
__le16 alignment;
} __attribute__((packed));
+struct onwire_segment_t {
+ // crypto-processed segment can be expanded on-wire because of:
+ // * padding to achieve CRYPTO_BLOCK_SIZE alignment,
+ // * authentication tag. It's appended at the end of message.
+ // See RxHandler::get_extra_size_at_final().
+ __le32 onwire_length;
+
+ struct ceph::msgr::v2::segment_t logical;
+} __attribute__((packed));
+
+struct SegmentIndex {
+ struct Msg {
+ static constexpr std::size_t HEADER = 0;
+ static constexpr std::size_t FRONT = 1;
+ static constexpr std::size_t MIDDLE = 2;
+ static constexpr std::size_t DATA = 3;
+ };
+
+ struct Frame {
+ static constexpr std::size_t PAYLOAD = 0;
+ };
+};
+
static constexpr uint8_t CRYPTO_BLOCK_SIZE { 16 };
static constexpr std::size_t MAX_NUM_SEGMENTS = 4;
// * CRC32 for MAX_NUM_SEGMENTS -- in plain mode,
// * cipher-specific data (e.g. auth tag for AES-GCM).
union epilogue_block_t {
- // TODO: add crc32 for plain mode
- std::array<uint8_t, CRYPTO_BLOCK_SIZE> auth_tag;
+ char auth_tag[CRYPTO_BLOCK_SIZE];
+ std::array<__le32, MAX_NUM_SEGMENTS> crc_values;
};
static_assert(sizeof(epilogue_block_t) % CRYPTO_BLOCK_SIZE == 0);
static_assert(std::is_standard_layout<epilogue_block_t>::value);
ceph::bufferlist &get_buffer() {
fill_preamble({segment_t{payload.length() - FRAME_PREAMBLE_SIZE,
segment_t::DEFAULT_ALIGNMENT}});
+
+ epilogue_block_t epilogue;
+ ::memset(&epilogue, 0, sizeof(epilogue));
+
+ ceph::bufferlist::const_iterator hdriter(&this->payload, FRAME_PREAMBLE_SIZE);
+ epilogue.crc_values[SegmentIndex::Frame::PAYLOAD] =
+ hdriter.crc32c(hdriter.get_remaining(), -1);
+ this->payload.append(reinterpret_cast<const char*>(&epilogue), sizeof(epilogue));
+
return payload;
}
};
session_stream_handlers.tx->authenticated_encrypt_update(
std::move(c.payload));
c.payload = session_stream_handlers.tx->authenticated_encrypt_final();
+ } else {
+ epilogue_block_t epilogue;
+ ::memset(&epilogue, 0, sizeof(epilogue));
+
+ ceph::bufferlist::const_iterator hdriter(&c.payload, FRAME_PREAMBLE_SIZE);
+ epilogue.crc_values[SegmentIndex::Frame::PAYLOAD] =
+ hdriter.crc32c(hdriter.get_remaining(), -1);
+ c.payload.append(reinterpret_cast<const char*>(&epilogue), sizeof(epilogue));
}
return c;
}
return this->payload;
}
- static MessageHeaderFrame Encode(const ceph_msg_header2 &msg_header,
- const uint32_t front_len,
- const uint32_t middle_len,
- const uint32_t data_len) {
+ static MessageHeaderFrame Encode(ceph::crypto::onwire::rxtx_t &session_stream_handlers,
+ const ceph_msg_header2 &msg_header,
+ const ceph::bufferlist& front,
+ const ceph::bufferlist& middle,
+ const ceph::bufferlist& data) {
MessageHeaderFrame f =
PayloadFrame<MessageHeaderFrame, ceph_msg_header2>::Encode(msg_header);
// FIXME: plainsize -> ciphersize; for AES-GCM they are equall apart from auth tag size
f.fill_preamble({
segment_t{ f.payload.length() - FRAME_PREAMBLE_SIZE,
- segment_t::DEFAULT_ALIGNMENT },
- segment_t{ front_len, segment_t::DEFAULT_ALIGNMENT },
- segment_t{ middle_len, segment_t::DEFAULT_ALIGNMENT },
- segment_t{ data_len, segment_t::DEFERRED_ALLOCATION },
+ segment_t::DEFAULT_ALIGNMENT },
+ segment_t{ front.length(), segment_t::DEFAULT_ALIGNMENT },
+ segment_t{ middle.length(), segment_t::DEFAULT_ALIGNMENT },
+ segment_t{ data.length(), segment_t::DEFERRED_ALLOCATION },
});
+
+ // FIXME: plainsize -> ciphersize; for AES-GCM they are equall apart from auth tag size
+ if (session_stream_handlers.tx) {
+ // let's cipher allocate one huge buffer for entire ciphertext.
+ // NOTE: ultimately we'll align these sizes to cipher's block size.
+ // AES-GCM can live without that as it's basically stream cipher.
+ session_stream_handlers.tx->reset_tx_handler({
+ f.payload.length(),
+ front.length(),
+ middle.length(),
+ data.length()
+ });
+
+ ceph_assert(f.payload.length());
+ session_stream_handlers.tx->authenticated_encrypt_update(
+ std::move(f.payload));
+
+ // TODO: switch TxHandler from `bl&&` to `const bl&`.
+ if (front.length()) {
+ session_stream_handlers.tx->authenticated_encrypt_update(front);
+ }
+ if (middle.length()) {
+ session_stream_handlers.tx->authenticated_encrypt_update(middle);
+ }
+ if (data.length()) {
+ session_stream_handlers.tx->authenticated_encrypt_update(data);
+ }
+
+ // auth tag will be appended at the end
+ f.payload = session_stream_handlers.tx->authenticated_encrypt_final();
+ } else {
+ f.payload.append(front);
+ f.payload.append(middle);
+ f.payload.append(data);
+
+ epilogue_block_t epilogue;
+ ceph::bufferlist::const_iterator hdriter(&f.payload, FRAME_PREAMBLE_SIZE);
+ epilogue.crc_values[SegmentIndex::Msg::HEADER] =
+ hdriter.crc32c(hdriter.get_remaining(), -1);
+ epilogue.crc_values[SegmentIndex::Msg::FRONT] = front.crc32c(-1),
+ epilogue.crc_values[SegmentIndex::Msg::MIDDLE] = middle.crc32c(-1),
+ epilogue.crc_values[SegmentIndex::Msg::DATA] = data.crc32c(-1),
+
+ f.payload.append(reinterpret_cast<const char*>(&epilogue), sizeof(epilogue));
+ }
+
return f;
}