diff options
author | Daniel Baumann <daniel.baumann@progress-linux.org> | 2024-04-07 18:45:59 +0000 |
---|---|---|
committer | Daniel Baumann <daniel.baumann@progress-linux.org> | 2024-04-07 18:45:59 +0000 |
commit | 19fcec84d8d7d21e796c7624e521b60d28ee21ed (patch) | |
tree | 42d26aa27d1e3f7c0b8bd3fd14e7d7082f5008dc /src/auth/cephx/CephxSessionHandler.cc | |
parent | Initial commit. (diff) | |
download | ceph-19fcec84d8d7d21e796c7624e521b60d28ee21ed.tar.xz ceph-19fcec84d8d7d21e796c7624e521b60d28ee21ed.zip |
Adding upstream version 16.2.11+ds.upstream/16.2.11+dsupstream
Signed-off-by: Daniel Baumann <daniel.baumann@progress-linux.org>
Diffstat (limited to 'src/auth/cephx/CephxSessionHandler.cc')
-rw-r--r-- | src/auth/cephx/CephxSessionHandler.cc | 194 |
1 files changed, 194 insertions, 0 deletions
diff --git a/src/auth/cephx/CephxSessionHandler.cc b/src/auth/cephx/CephxSessionHandler.cc new file mode 100644 index 000000000..d1417d6ca --- /dev/null +++ b/src/auth/cephx/CephxSessionHandler.cc @@ -0,0 +1,194 @@ +// -*- mode:C++; tab-width:8; c-basic-offset:2; indent-tabs-mode:t -*- +// vim: ts=8 sw=2 smarttab +/* + * Ceph - scalable distributed file system + * + * Copyright (C) 2004-2009 Sage Weil <sage@newdream.net> + * + * This is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License version 2.1, as published by the Free Software + * Foundation. See file COPYING. + * + */ + +#include "CephxSessionHandler.h" +#include "CephxProtocol.h" + +#include <errno.h> +#include <sstream> + +#include "common/config.h" +#include "include/ceph_features.h" +#include "msg/Message.h" + +#define dout_subsys ceph_subsys_auth + +namespace { +#ifdef WITH_SEASTAR + crimson::common::ConfigProxy& conf(CephContext*) { + return crimson::common::local_conf(); + } +#else + ConfigProxy& conf(CephContext* cct) { + return cct->_conf; + } +#endif +} + +int CephxSessionHandler::_calc_signature(Message *m, uint64_t *psig) +{ + const ceph_msg_header& header = m->get_header(); + const ceph_msg_footer& footer = m->get_footer(); + + if (!HAVE_FEATURE(features, CEPHX_V2)) { + // legacy pre-mimic behavior for compatibility + + // optimized signature calculation + // - avoid temporary allocated buffers from encode_encrypt[_enc_bl] + // - skip the leading 4 byte wrapper from encode_encrypt + struct { + __u8 v; + ceph_le64 magic; + ceph_le32 len; + ceph_le32 header_crc; + ceph_le32 front_crc; + ceph_le32 middle_crc; + ceph_le32 data_crc; + } __attribute__ ((packed)) sigblock = { + 1, init_le64(AUTH_ENC_MAGIC), init_le32(4*4), + init_le32(header.crc), init_le32(footer.front_crc), + init_le32(footer.middle_crc), init_le32(footer.data_crc) + }; + + char exp_buf[CryptoKey::get_max_outbuf_size(sizeof(sigblock))]; + + try { + const CryptoKey::in_slice_t in { + sizeof(sigblock), + reinterpret_cast<const unsigned char*>(&sigblock) + }; + const CryptoKey::out_slice_t out { + sizeof(exp_buf), + reinterpret_cast<unsigned char*>(&exp_buf) + }; + key.encrypt(cct, in, out); + } catch (std::exception& e) { + lderr(cct) << __func__ << " failed to encrypt signature block" << dendl; + return -1; + } + + *psig = *reinterpret_cast<ceph_le64*>(exp_buf); + } else { + // newer mimic+ signatures + struct { + ceph_le32 header_crc; + ceph_le32 front_crc; + ceph_le32 front_len; + ceph_le32 middle_crc; + ceph_le32 middle_len; + ceph_le32 data_crc; + ceph_le32 data_len; + ceph_le32 seq_lower_word; + } __attribute__ ((packed)) sigblock = { + init_le32(header.crc), + init_le32(footer.front_crc), + init_le32(header.front_len), + init_le32(footer.middle_crc), + init_le32(header.middle_len), + init_le32(footer.data_crc), + init_le32(header.data_len), + init_le32(header.seq) + }; + + char exp_buf[CryptoKey::get_max_outbuf_size(sizeof(sigblock))]; + + try { + const CryptoKey::in_slice_t in { + sizeof(sigblock), + reinterpret_cast<const unsigned char*>(&sigblock) + }; + const CryptoKey::out_slice_t out { + sizeof(exp_buf), + reinterpret_cast<unsigned char*>(&exp_buf) + }; + key.encrypt(cct, in, out); + } catch (std::exception& e) { + lderr(cct) << __func__ << " failed to encrypt signature block" << dendl; + return -1; + } + + struct enc { + ceph_le64 a, b, c, d; + } *penc = reinterpret_cast<enc*>(exp_buf); + *psig = penc->a ^ penc->b ^ penc->c ^ penc->d; + } + + ldout(cct, 10) << __func__ << " seq " << m->get_seq() + << " front_crc_ = " << footer.front_crc + << " middle_crc = " << footer.middle_crc + << " data_crc = " << footer.data_crc + << " sig = " << *psig + << dendl; + return 0; +} + +int CephxSessionHandler::sign_message(Message *m) +{ + // If runtime signing option is off, just return success without signing. + if (!conf(cct)->cephx_sign_messages) { + return 0; + } + + uint64_t sig; + int r = _calc_signature(m, &sig); + if (r < 0) + return r; + + ceph_msg_footer& f = m->get_footer(); + f.sig = sig; + f.flags = (unsigned)f.flags | CEPH_MSG_FOOTER_SIGNED; + ldout(cct, 20) << "Putting signature in client message(seq # " << m->get_seq() + << "): sig = " << sig << dendl; + return 0; +} + +int CephxSessionHandler::check_message_signature(Message *m) +{ + // If runtime signing option is off, just return success without checking signature. + if (!conf(cct)->cephx_sign_messages) { + return 0; + } + if ((features & CEPH_FEATURE_MSG_AUTH) == 0) { + // it's fine, we didn't negotiate this feature. + return 0; + } + + uint64_t sig; + int r = _calc_signature(m, &sig); + if (r < 0) + return r; + + if (sig != m->get_footer().sig) { + // Should have been signed, but signature check failed. PLR + if (!(m->get_footer().flags & CEPH_MSG_FOOTER_SIGNED)) { + ldout(cct, 0) << "SIGN: MSG " << m->get_seq() << " Sender did not set CEPH_MSG_FOOTER_SIGNED." << dendl; + } + ldout(cct, 0) << "SIGN: MSG " << m->get_seq() << " Message signature does not match contents." << dendl; + ldout(cct, 0) << "SIGN: MSG " << m->get_seq() << "Signature on message:" << dendl; + ldout(cct, 0) << "SIGN: MSG " << m->get_seq() << " sig: " << m->get_footer().sig << dendl; + ldout(cct, 0) << "SIGN: MSG " << m->get_seq() << "Locally calculated signature:" << dendl; + ldout(cct, 0) << "SIGN: MSG " << m->get_seq() << " sig_check:" << sig << dendl; + + // For the moment, printing an error message to the log and + // returning failure is sufficient. In the long term, we should + // probably have code parsing the log looking for this kind of + // security failure, particularly when there are large numbers of + // them, since the latter is a potential sign of an attack. PLR + + ldout(cct, 0) << "Signature failed." << dendl; + return (SESSION_SIGNATURE_FAILURE); + } + + return 0; +} |