]> git.apps.os.sepia.ceph.com Git - ceph.git/commitdiff
msg/async, v2: implement epilogue handling in secure mode.
authorRadoslaw Zarzynski <rzarzyns@redhat.com>
Tue, 26 Feb 2019 00:01:34 +0000 (01:01 +0100)
committerRadoslaw Zarzynski <rzarzyns@redhat.com>
Thu, 28 Feb 2019 20:42:39 +0000 (21:42 +0100)
Signed-off-by: Radoslaw Zarzynski <rzarzyns@redhat.com>
src/msg/async/ProtocolV2.cc
src/msg/async/ProtocolV2.h
src/msg/async/frames_v2.h

index 9a29dcde3bf010c3df8468587da82ddfa349fa3d..8a19b7759984cc95ccf5f6ac50016c615acbea50 100644 (file)
@@ -1098,7 +1098,6 @@ CtPtr ProtocolV2::handle_read_frame_preamble_main(char *buffer, int r) {
 
     rx_segments_desc.clear();
     rx_segments_data.clear();
-    next_payload_len = 0;
 
     if (main_preamble.num_segments > MAX_NUM_SEGMENTS) {
       ldout(cct, 30) << __func__
@@ -1115,14 +1114,6 @@ CtPtr ProtocolV2::handle_read_frame_preamble_main(char *buffer, int r) {
        get_onwire_size(main_preamble.segments[idx].length),
        main_preamble.segments[idx]
       });
-      next_payload_len += rx_segments_desc.back().onwire_length;
-    }
-
-    if (session_stream_handlers.rx) {
-      rx_segments_desc.back().onwire_length += \
-       session_stream_handlers.rx->get_extra_size_at_final();
-      next_payload_len += \
-       session_stream_handlers.rx->get_extra_size_at_final();
     }
   }
 
@@ -1136,7 +1127,7 @@ CtPtr ProtocolV2::handle_read_frame_preamble_main(char *buffer, int r) {
 }
 
 CtPtr ProtocolV2::handle_read_frame_dispatch() {
-  ldout(cct, 10) << __func__ << " next payload_len=" << next_payload_len
+  ldout(cct, 10) << __func__
                  << " tag=" << static_cast<uint32_t>(next_tag) << dendl;
 
   switch (next_tag) {
@@ -1238,8 +1229,12 @@ CtPtr ProtocolV2::handle_read_frame_segment(char *buffer, int r) {
   }
 
   if (rx_segments_desc.size() == rx_segments_data.size()) {
-    // OK, all segments planned to read are read. Can go with dispatch.
-    return handle_read_frame_dispatch();
+    // 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();
+    }
   } else {
     // TODO: for makeshift only. This will be more generic and throttled
     return read_frame_segment();
@@ -1378,7 +1373,7 @@ CtPtr ProtocolV2::handle_message() {
   front.clear();
   middle.clear();
   data.clear();
-  extra.clear();
+  epilogue.clear();
   current_header = header;
 
   // front
@@ -1389,9 +1384,6 @@ CtPtr ProtocolV2::handle_message() {
   ceph_assert(!middle.length());
   middle = std::move(rx_segments_data[SegmentIndex::Msg::MIDDLE]);
 
-  next_payload_len -= sizeof(ceph_msg_header2);
-  next_payload_len -= front.length();
-  next_payload_len -= middle.length();
   return read_message_data_prepare();
 }
 
@@ -1438,19 +1430,39 @@ CtPtr ProtocolV2::read_message_data() {
     return READB(read_len, bp.c_str(), handle_message_data);
   }
 
-  next_payload_len -= rx_segments_desc[SegmentIndex::Msg::DATA].logical.length;
-  if (next_payload_len) {
+  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();
+  }
+}
+
+CtPtr ProtocolV2::handle_read_frame_epilogue_main(char *buffer, int r) {
+  ldout(cct, 20) << __func__ << " r=" << r << dendl;
+
+  if (r < 0) {
+    ldout(cct, 1) << __func__ << " read data error " << dendl;
+    return _fault();
+  }
+
+  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__ << " reading message payload extra bytes left="
-                  << next_payload_len << dendl;
+    ldout(cct, 1) << __func__ << " read frame epilogue bytes="
+                  << FRAME_EPILOGUE_SIZE << dendl;
     ceph_assert(session_stream_handlers.rx && session_stream_handlers.tx &&
                auth_meta->is_mode_secure());
-    extra.push_back(buffer::create(next_payload_len));
-    return READB(next_payload_len, extra.c_str(), handle_message_extra_bytes);
+    ceph_assert(FRAME_EPILOGUE_SIZE == \
+      session_stream_handlers.rx->get_extra_size_at_final());
+
+    // I expect that ::temp_buffer is being used here.
+    epilogue.push_back(buffer::create_static(FRAME_EPILOGUE_SIZE, buffer));
   }
 
-  state = READ_MESSAGE_COMPLETE;
+  // FIXME
+  rx_segments_data.back().claim_append(epilogue);
   return handle_read_frame_dispatch();
 }
 
@@ -1472,18 +1484,6 @@ CtPtr ProtocolV2::handle_message_data(char *buffer, int r) {
   return CONTINUE(read_message_data);
 }
 
-CtPtr ProtocolV2::handle_message_extra_bytes(char *buffer, int r) {
-  ldout(cct, 20) << __func__ << " r=" << r << dendl;
-
-  if (r < 0) {
-    ldout(cct, 1) << __func__ << " read message extra bytes error " << dendl;
-    return _fault();
-  }
-
-  state = READ_MESSAGE_COMPLETE;
-  return handle_read_frame_dispatch();
-}
-
 CtPtr ProtocolV2::handle_message_complete() {
   ldout(cct, 20) << __func__ << dendl;
 
@@ -1517,8 +1517,6 @@ CtPtr ProtocolV2::handle_message_complete() {
                          current_header.data_crc, 0, current_header.flags};
 
   if (auth_meta->is_mode_secure()) {
-    //msg_payload.claim_append(extra);
-
     if (front.length()) {
       front = session_stream_handlers.rx->authenticated_decrypt_update(
         std::move(front), segment_t::DEFAULT_ALIGNMENT);
@@ -1527,13 +1525,11 @@ CtPtr ProtocolV2::handle_message_complete() {
       middle = session_stream_handlers.rx->authenticated_decrypt_update(
         std::move(middle), segment_t::DEFAULT_ALIGNMENT);
     }
-    if (data.length()) {
-      data = session_stream_handlers.rx->authenticated_decrypt_update(
-        std::move(data), segment_t::DEFAULT_ALIGNMENT);
-    }
+    // FIXME: append epilogue. This is really ugly.
+    data.claim_append(rx_segments_data[SegmentIndex::Msg::DATA]);
     try {
-      session_stream_handlers.rx->authenticated_decrypt_update_final(
-       std::move(extra), segment_t::DEFAULT_ALIGNMENT);
+      data = session_stream_handlers.rx->authenticated_decrypt_update_final(
+       std::move(data), segment_t::DEFAULT_ALIGNMENT);
     } catch (ceph::crypto::onwire::MsgAuthError &e) {
       ldout(cct, 5) << __func__ << " message authentication failed: "
                    << e.what() << dendl;
@@ -1662,7 +1658,7 @@ CtPtr ProtocolV2::handle_message_complete() {
   front.clear();
   middle.clear();
   data.clear();
-  extra.clear();
+  epilogue.clear();
 
   // we might have been reused by another connection
   // let's check if that is the case
index a549ec80d6f14c8905099169ecc74ea21286e84d..f564452c295a7d3076820bbc7439e47fd5baa587 100644 (file)
@@ -114,6 +114,7 @@ public:
   boost::container::static_vector<ceph::bufferlist,
                                  ceph::msgr::v2::MAX_NUM_SEGMENTS> rx_segments_data;
 
+  ceph::bufferlist epilogue;
 private:
 
   ceph::msgr::v2::Tag sent_tag;
@@ -125,7 +126,7 @@ private:
   unsigned msg_left;
   bufferlist data_buf;
   bufferlist::iterator data_blp;
-  bufferlist front, middle, data, extra;
+  bufferlist front, middle, data;
 
   bool keepalive;
 
@@ -170,18 +171,19 @@ private:
   CONTINUATION_DECL(ProtocolV2, read_frame);
   READ_HANDLER_CONTINUATION_DECL(ProtocolV2, handle_read_frame_preamble_main);
   READ_HANDLER_CONTINUATION_DECL(ProtocolV2, handle_read_frame_segment);
+  READ_HANDLER_CONTINUATION_DECL(ProtocolV2, handle_read_frame_epilogue_main);
   CONTINUATION_DECL(ProtocolV2, throttle_message);
   CONTINUATION_DECL(ProtocolV2, throttle_bytes);
   CONTINUATION_DECL(ProtocolV2, throttle_dispatch_queue);
   CONTINUATION_DECL(ProtocolV2, read_message_data);
   READ_HANDLER_CONTINUATION_DECL(ProtocolV2, handle_message_data);
-  READ_HANDLER_CONTINUATION_DECL(ProtocolV2, handle_message_extra_bytes);
 
   Ct<ProtocolV2> *read_frame();
   Ct<ProtocolV2> *handle_read_frame_preamble_main(char *buffer, int r);
-  Ct<ProtocolV2> *handle_read_frame_dispatch();
   Ct<ProtocolV2> *read_frame_segment();
   Ct<ProtocolV2> *handle_read_frame_segment(char *buffer, int r);
+  Ct<ProtocolV2> *handle_read_frame_epilogue_main(char *buffer, int r);
+  Ct<ProtocolV2> *handle_read_frame_dispatch();
   Ct<ProtocolV2> *handle_frame_payload();
 
   Ct<ProtocolV2> *ready();
@@ -193,7 +195,6 @@ private:
   Ct<ProtocolV2> *read_message_data_prepare();
   Ct<ProtocolV2> *read_message_data();
   Ct<ProtocolV2> *handle_message_data(char *buffer, int r);
-  Ct<ProtocolV2> *handle_message_extra_bytes(char *buffer, int r);
   Ct<ProtocolV2> *handle_message_complete();
 
   Ct<ProtocolV2> *handle_keepalive2(ceph::bufferlist &payload);
index 112b755345ed359c9ead3724da2431ef6a5f6be3..31be035455b0d17b0d6f1eab6ead561b9aa1220c 100644 (file)
@@ -91,8 +91,20 @@ struct preamble_block_t {
 static_assert(sizeof(preamble_block_t) % CRYPTO_BLOCK_SIZE == 0);
 static_assert(std::is_standard_layout<preamble_block_t>::value);
 
+// V2 epilogue conveys integrity/authentication information. It's added
+// at the end of each frame holds:
+//  * 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;
+};
+static_assert(sizeof(epilogue_block_t) % CRYPTO_BLOCK_SIZE == 0);
+static_assert(std::is_standard_layout<epilogue_block_t>::value);
+
 
 static constexpr uint32_t FRAME_PREAMBLE_SIZE = sizeof(preamble_block_t);
+static constexpr uint32_t FRAME_EPILOGUE_SIZE = sizeof(epilogue_block_t);
 
 template <class T>
 struct Frame {