]> git.apps.os.sepia.ceph.com Git - ceph.git/commitdiff
msg/async, v2: epilogue size is variable in secure mode.
authorRadoslaw Zarzynski <rzarzyns@redhat.com>
Fri, 1 Mar 2019 19:18:11 +0000 (20:18 +0100)
committerRadoslaw Zarzynski <rzarzyns@redhat.com>
Fri, 1 Mar 2019 19:28:13 +0000 (20:28 +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 20b3f8d151c08cb4fbd8c52b3cc88680e8defe42..ff69c657c3854d0d3fb6ad0727ab9858d97cef53 100644 (file)
@@ -695,6 +695,16 @@ uint32_t ProtocolV2::get_onwire_size(uint32_t logical_size) const {
   return logical_size;
 }
 
+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.
+  if (session_stream_handlers.rx) {
+    return session_stream_handlers.rx->get_extra_size_at_final();
+  } else {
+    return FRAME_CRC_EPILOGUE_SIZE;
+  }
+}
+
 CtPtr ProtocolV2::read(CONTINUATION_PARAM(next, ProtocolV2, char *, int),
                        int len, char *buffer) {
   if (!buffer) {
@@ -1163,7 +1173,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.
-    return READ(FRAME_EPILOGUE_SIZE, handle_read_frame_epilogue_main);
+    return READ(get_epilogue_size(), handle_read_frame_epilogue_main);
   } else {
     // TODO: for makeshift only. This will be more generic and throttled
     return read_frame_segment();
@@ -1264,23 +1274,17 @@ CtPtr ProtocolV2::handle_read_frame_epilogue_main(char *buffer, int r)
     return _fault();
   }
 
-  auto& epilogue = reinterpret_cast<epilogue_block_t&>(*buffer);
-
   // 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="
-                  << FRAME_EPILOGUE_SIZE << dendl;
-
-    ceph_assert(session_stream_handlers.rx);
-    ceph_assert(FRAME_EPILOGUE_SIZE == \
-      session_stream_handlers.rx->get_extra_size_at_final());
+                  << get_epilogue_size() << dendl;
 
     // 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));
+    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);
@@ -1291,6 +1295,8 @@ CtPtr ProtocolV2::handle_read_frame_epilogue_main(char *buffer, int r)
       return _fault();
     }
   } else {
+    auto& epilogue = reinterpret_cast<epilogue_crc_block_t&>(*buffer);
+
     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);
index b6acd2be4db4ab15c5f1e353b07fb7ff5e29e78d..ab58a9a5da9d58822eb8280de8fd22282573fcb9 100644 (file)
@@ -232,6 +232,7 @@ private:
   Ct<ProtocolV2> *server_ready();
 
   uint32_t get_onwire_size(uint32_t logical_size) const;
+  uint32_t get_epilogue_size() const;
 };
 
 #endif /* _MSG_ASYNC_PROTOCOL_V2_ */
index 507dc471a8abdd5625bf2a16e597f31c36ca3471..e7f300d58a50e55b0c8fab366333d4bcbe5cbc68 100644 (file)
@@ -104,20 +104,30 @@ 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 {
-  char auth_tag[CRYPTO_BLOCK_SIZE];
+// Each Frame has an epilogue for integrity or authenticity validation.
+// For plain mode it's quite straightforward - the structure stores up
+// to MAX_NUM_SEGMENTS crc32 checksums, one per each segment.
+// For secure mode things become very different. The fundamental thing
+// is that epilogue format is **an implementation detail of particular
+// cipher**. ProtocolV2 only knows:
+//   * where the data is placed (always at the end of ciphertext),
+//   * how long it is. RxHandler provides get_extra_size_at_final() but
+//     ProtocolV2 has NO WAY to alter this.
+//
+// The intention behind the contract is to provide flexibility of cipher
+// selection. Currently AES in GCM mode is used and epilogue conveys its
+// *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 {
   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);
+static_assert(sizeof(epilogue_crc_block_t) % CRYPTO_BLOCK_SIZE == 0);
+static_assert(std::is_standard_layout<epilogue_crc_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);
+static constexpr uint32_t FRAME_CRC_EPILOGUE_SIZE = sizeof(epilogue_crc_block_t);
 
 template <class T>
 struct Frame {
@@ -167,7 +177,7 @@ public:
     fill_preamble({segment_t{payload.length() - FRAME_PREAMBLE_SIZE,
                    segment_t::DEFAULT_ALIGNMENT}});
 
-    epilogue_block_t epilogue;
+    epilogue_crc_block_t epilogue;
     ::memset(&epilogue, 0, sizeof(epilogue));
 
     ceph::bufferlist::const_iterator hdriter(&this->payload, FRAME_PREAMBLE_SIZE);
@@ -373,7 +383,7 @@ struct SignedEncryptedFrame : public PayloadFrame<T, Args...> {
           std::move(c.payload));
       c.payload = session_stream_handlers.tx->authenticated_encrypt_final();
     } else {
-      epilogue_block_t epilogue;
+      epilogue_crc_block_t epilogue;
       ::memset(&epilogue, 0, sizeof(epilogue));
 
       ceph::bufferlist::const_iterator hdriter(&c.payload, FRAME_PREAMBLE_SIZE);
@@ -637,7 +647,7 @@ struct MessageHeaderFrame
       // auth tag will be appended at the end
       f.payload = session_stream_handlers.tx->authenticated_encrypt_final();
     } else {
-      epilogue_block_t epilogue;
+      epilogue_crc_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);