uint32_t ProtocolV2::get_epilogue_size() const {
// In secure mode size of epilogue is flexible and depends on particular
- // cipher implementation. See the comment for epilogue_crc_block_t.
+ // cipher implementation. See the comment for epilogue_secure_block_t or
+ // epilogue_plain_block_t.
if (session_stream_handlers.rx) {
- return session_stream_handlers.rx->get_extra_size_at_final();
+ return FRAME_SECURE_EPILOGUE_SIZE + \
+ session_stream_handlers.rx->get_extra_size_at_final();
} else {
- return FRAME_CRC_EPILOGUE_SIZE;
+ return FRAME_PLAIN_EPILOGUE_SIZE;
}
}
return _fault();
}
+ __u8 late_flags;
+
// FIXME: if (auth_meta->is_mode_secure()) {
if (session_stream_handlers.rx) {
- // if we still have more bytes to read is because we signed or encrypted
- // the message payload
ldout(cct, 1) << __func__ << " read frame epilogue bytes="
<< get_epilogue_size() << dendl;
- // I expect that ::temp_buffer is being used here.
+ // decrypt epilogue and authenticate entire frame.
ceph::bufferlist epilogue_bl;
- epilogue_bl.push_back(buffer::create_static(get_epilogue_size(),
- buffer));
- try {
- session_stream_handlers.rx->authenticated_decrypt_update_final(
- std::move(epilogue_bl), segment_t::DEFAULT_ALIGNMENT);
- } catch (ceph::crypto::onwire::MsgAuthError &e) {
- ldout(cct, 5) << __func__ << " message authentication failed: "
- << e.what() << dendl;
- ceph_assert("oops" == nullptr);
- return _fault();
+ {
+ epilogue_bl.push_back(buffer::create_static(get_epilogue_size(),
+ buffer));
+ try {
+ epilogue_bl =
+ session_stream_handlers.rx->authenticated_decrypt_update_final(
+ 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();
+ }
}
+ auto& epilogue =
+ reinterpret_cast<epilogue_plain_block_t&>(*epilogue_bl.c_str());
+ late_flags = epilogue.late_flags;
} else {
- auto& epilogue = reinterpret_cast<epilogue_crc_block_t&>(*buffer);
+ auto& epilogue = reinterpret_cast<epilogue_plain_block_t&>(*buffer);
for (std::uint8_t idx = 0; idx < rx_segments_data.size(); idx++) {
const __u32 expected_crc = epilogue.crc_values[idx];
<< dendl;
}
}
+ late_flags = epilogue.late_flags;
}
- return handle_read_frame_dispatch();
+ // we do have a mechanism that allows transmitter to start sending message
+ // and abort after putting entire data field on wire. This will be used by
+ // the kernel client to avoid unnecessary buffering.
+ if (late_flags & FRAME_FLAGS_LATEABRT) {
+ reset_throttle();
+ state = READY;
+ return CONTINUE(read_frame);
+ } else {
+ return handle_read_frame_dispatch();
+ }
}
CtPtr ProtocolV2::handle_message() {
0};
ceph_msg_footer footer{0, 0, 0, 0, current_header.flags};
- // we do have a mechanism that allows transmitter to start sending message
- // and abort after putting entire data field on wire. This will be used by
- // the kernel client to avoid unnecessary buffering.
- if (current_header.flags & CEPH_MSG_FOOTER_LATEABRT) {
- ceph_assert(state == THROTTLE_DONE);
-
- reset_throttle();
- state = READY;
- return CONTINUE(read_frame);
- }
-
Message *message = decode_message(cct, 0, header, footer,
rx_segments_data[SegmentIndex::Msg::FRONT],
rx_segments_data[SegmentIndex::Msg::MIDDLE],
// *auth tag* (following OpenSSL's terminology). However, it would be OK
// to switch to e.g. AES128-CBC + HMAC-SHA512 without affecting protocol
// (expect the cipher negotiation, of course).
-struct epilogue_crc_block_t {
+//
+// In addition to integrity/authenticity data each variant of epilogue
+// conveys late_flags. The initial user of this field will be the late
+// frame abortion facility.
+struct epilogue_plain_block_t {
+ __u8 late_flags;
std::array<__le32, MAX_NUM_SEGMENTS> crc_values;
-};
-static_assert(sizeof(epilogue_crc_block_t) % CRYPTO_BLOCK_SIZE == 0);
-static_assert(std::is_standard_layout<epilogue_crc_block_t>::value);
+} __attribute__((packed));
+static_assert(std::is_standard_layout<epilogue_plain_block_t>::value);
+
+struct epilogue_secure_block_t {
+ __u8 late_flags;
+ __u8 padding[CRYPTO_BLOCK_SIZE - sizeof(late_flags)];
+
+ __u8 ciphers_private_data[];
+} __attribute__((packed));
+static_assert(sizeof(epilogue_secure_block_t) % CRYPTO_BLOCK_SIZE == 0);
+static_assert(std::is_standard_layout<epilogue_secure_block_t>::value);
static constexpr uint32_t FRAME_PREAMBLE_SIZE = sizeof(preamble_block_t);
-static constexpr uint32_t FRAME_CRC_EPILOGUE_SIZE = sizeof(epilogue_crc_block_t);
+static constexpr uint32_t FRAME_PLAIN_EPILOGUE_SIZE =
+ sizeof(epilogue_plain_block_t);
+static constexpr uint32_t FRAME_SECURE_EPILOGUE_SIZE =
+ sizeof(epilogue_secure_block_t);
+
+#define FRAME_FLAGS_LATEABRT (1<<0) /* frame was aborted after txing data */
template <class T>
struct Frame {
fill_preamble({segment_t{payload.length() - FRAME_PREAMBLE_SIZE,
segment_t::DEFAULT_ALIGNMENT}});
- epilogue_crc_block_t epilogue;
+ epilogue_plain_block_t epilogue;
::memset(&epilogue, 0, sizeof(epilogue));
ceph::bufferlist::const_iterator hdriter(&this->payload, FRAME_PREAMBLE_SIZE);
segment_t::DEFAULT_ALIGNMENT}});
if (session_stream_handlers.tx) {
+ epilogue_secure_block_t epilogue;
+ ::memset(&epilogue, 0, sizeof(epilogue));
+ c.payload.append(reinterpret_cast<const char*>(&epilogue), sizeof(epilogue));
+
ceph_assert(session_stream_handlers.tx);
session_stream_handlers.tx->reset_tx_handler({c.payload.length()});
std::move(c.payload));
c.payload = session_stream_handlers.tx->authenticated_encrypt_final();
} else {
- epilogue_crc_block_t epilogue;
+ epilogue_plain_block_t epilogue;
::memset(&epilogue, 0, sizeof(epilogue));
ceph::bufferlist::const_iterator hdriter(&c.payload, FRAME_PREAMBLE_SIZE);
session_stream_handlers.tx->authenticated_encrypt_update(data);
}
+ // craft the secure's mode epilogue
+ {
+ epilogue_secure_block_t epilogue;
+ ::memset(&epilogue, 0, sizeof(epilogue));
+ ceph::bufferlist epilogue_bl;
+ epilogue_bl.append(reinterpret_cast<const char*>(&epilogue),
+ sizeof(epilogue));
+ session_stream_handlers.tx->authenticated_encrypt_update(epilogue_bl);
+ }
+
// auth tag will be appended at the end
f.payload = session_stream_handlers.tx->authenticated_encrypt_final();
} else {
- epilogue_crc_block_t epilogue;
+ epilogue_plain_block_t epilogue;
+ ::memset(&epilogue, 0, sizeof(epilogue));
+
ceph::bufferlist::const_iterator hdriter(&f.payload, FRAME_PREAMBLE_SIZE);
epilogue.crc_values[SegmentIndex::Msg::HEADER] =
hdriter.crc32c(hdriter.get_remaining(), -1);