]> git.apps.os.sepia.ceph.com Git - ceph.git/commitdiff
msg/async, v2: use frame epilogue for crc32 integrity checking.
authorRadoslaw Zarzynski <rzarzyns@redhat.com>
Wed, 27 Feb 2019 20:49:39 +0000 (21:49 +0100)
committerRadoslaw Zarzynski <rzarzyns@redhat.com>
Fri, 1 Mar 2019 01:50:49 +0000 (02:50 +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 28e3196a75c415c8491f2c279b4aef302c5ec2a5..71ed6065e7a4c0f0ab8f36dd0247ab9b054c30e6 100644 (file)
@@ -520,50 +520,12 @@ ssize_t ProtocolV2::write_message(Message *m, bool more) {
                     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;
@@ -1241,11 +1203,7 @@ 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 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();
@@ -1433,15 +1391,11 @@ CtPtr ProtocolV2::read_message_data() {
   }
 
   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) {
@@ -1449,10 +1403,7 @@ CtPtr ProtocolV2::handle_read_frame_epilogue_main(char *buffer, int r) {
     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) {
@@ -1464,14 +1415,36 @@ CtPtr ProtocolV2::handle_read_frame_epilogue_main(char *buffer, int r) {
     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();
index defc20561b02686bca0ba4dd586fc4cfe4f54ba3..1385885c9fdb00c278eae5e9c81d514ff938be28 100644 (file)
@@ -86,30 +86,7 @@ private:
 
 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;
index 08a1eaa3c8357bcc4bd205ec6733714297fd245f..f1c60db9a4f447badc58c6fabaf536542ce21889 100644 (file)
@@ -63,6 +63,29 @@ struct segment_t {
   __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;
@@ -96,8 +119,8 @@ static_assert(std::is_standard_layout<preamble_block_t>::value);
 //  * 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);
@@ -153,6 +176,15 @@ public:
   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;
   }
 };
@@ -350,6 +382,14 @@ struct SignedEncryptedFrame : public PayloadFrame<T, Args...> {
       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;
   }
@@ -561,20 +601,67 @@ struct MessageHeaderFrame
     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;
   }