1 // -*- mode:C++; tab-width:8; c-basic-offset:2; indent-tabs-mode:t -*-
2 // vim: ts=8 sw=2 smarttab
4 * Ceph - scalable distributed file system
6 * Copyright (C) 2004-2009 Sage Weil <sage@newdream.net>
8 * This is free software; you can redistribute it and/or
9 * modify it under the terms of the GNU Lesser General Public
10 * License version 2.1, as published by the Free Software
11 * Foundation. See file COPYING.
15 #include "CephxSessionHandler.h"
16 #include "CephxProtocol.h"
21 #include "common/config.h"
22 #include "include/ceph_features.h"
23 #include "msg/Message.h"
25 #define dout_subsys ceph_subsys_auth
29 crimson::common::ConfigProxy
& conf(CephContext
*) {
30 return crimson::common::local_conf();
33 ConfigProxy
& conf(CephContext
* cct
) {
39 int CephxSessionHandler::_calc_signature(Message
*m
, uint64_t *psig
)
41 const ceph_msg_header
& header
= m
->get_header();
42 const ceph_msg_footer
& footer
= m
->get_footer();
44 if (!HAVE_FEATURE(features
, CEPHX_V2
)) {
45 // legacy pre-mimic behavior for compatibility
47 // optimized signature calculation
48 // - avoid temporary allocated buffers from encode_encrypt[_enc_bl]
49 // - skip the leading 4 byte wrapper from encode_encrypt
58 } __attribute__ ((packed
)) sigblock
= {
59 1, ceph_le64(AUTH_ENC_MAGIC
), ceph_le32(4 * 4),
60 ceph_le32(header
.crc
), ceph_le32(footer
.front_crc
),
61 ceph_le32(footer
.middle_crc
), ceph_le32(footer
.data_crc
)
64 char exp_buf
[CryptoKey::get_max_outbuf_size(sizeof(sigblock
))];
67 const CryptoKey::in_slice_t in
{
69 reinterpret_cast<const unsigned char*>(&sigblock
)
71 const CryptoKey::out_slice_t out
{
73 reinterpret_cast<unsigned char*>(&exp_buf
)
75 key
.encrypt(cct
, in
, out
);
76 } catch (std::exception
& e
) {
77 lderr(cct
) << __func__
<< " failed to encrypt signature block" << dendl
;
81 *psig
= *reinterpret_cast<ceph_le64
*>(exp_buf
);
83 // newer mimic+ signatures
92 ceph_le32 seq_lower_word
;
93 } __attribute__ ((packed
)) sigblock
= {
94 ceph_le32(header
.crc
),
95 ceph_le32(footer
.front_crc
),
96 ceph_le32(header
.front_len
),
97 ceph_le32(footer
.middle_crc
),
98 ceph_le32(header
.middle_len
),
99 ceph_le32(footer
.data_crc
),
100 ceph_le32(header
.data_len
),
101 ceph_le32(header
.seq
)
104 char exp_buf
[CryptoKey::get_max_outbuf_size(sizeof(sigblock
))];
107 const CryptoKey::in_slice_t in
{
109 reinterpret_cast<const unsigned char*>(&sigblock
)
111 const CryptoKey::out_slice_t out
{
113 reinterpret_cast<unsigned char*>(&exp_buf
)
115 key
.encrypt(cct
, in
, out
);
116 } catch (std::exception
& e
) {
117 lderr(cct
) << __func__
<< " failed to encrypt signature block" << dendl
;
122 ceph_le64 a
, b
, c
, d
;
123 } *penc
= reinterpret_cast<enc
*>(exp_buf
);
124 *psig
= penc
->a
^ penc
->b
^ penc
->c
^ penc
->d
;
127 ldout(cct
, 10) << __func__
<< " seq " << m
->get_seq()
128 << " front_crc_ = " << footer
.front_crc
129 << " middle_crc = " << footer
.middle_crc
130 << " data_crc = " << footer
.data_crc
131 << " sig = " << *psig
136 int CephxSessionHandler::sign_message(Message
*m
)
138 // If runtime signing option is off, just return success without signing.
139 if (!conf(cct
)->cephx_sign_messages
) {
144 int r
= _calc_signature(m
, &sig
);
148 ceph_msg_footer
& f
= m
->get_footer();
150 f
.flags
= (unsigned)f
.flags
| CEPH_MSG_FOOTER_SIGNED
;
151 ldout(cct
, 20) << "Putting signature in client message(seq # " << m
->get_seq()
152 << "): sig = " << sig
<< dendl
;
156 int CephxSessionHandler::check_message_signature(Message
*m
)
158 // If runtime signing option is off, just return success without checking signature.
159 if (!conf(cct
)->cephx_sign_messages
) {
162 if ((features
& CEPH_FEATURE_MSG_AUTH
) == 0) {
163 // it's fine, we didn't negotiate this feature.
168 int r
= _calc_signature(m
, &sig
);
172 if (sig
!= m
->get_footer().sig
) {
173 // Should have been signed, but signature check failed. PLR
174 if (!(m
->get_footer().flags
& CEPH_MSG_FOOTER_SIGNED
)) {
175 ldout(cct
, 0) << "SIGN: MSG " << m
->get_seq() << " Sender did not set CEPH_MSG_FOOTER_SIGNED." << dendl
;
177 ldout(cct
, 0) << "SIGN: MSG " << m
->get_seq() << " Message signature does not match contents." << dendl
;
178 ldout(cct
, 0) << "SIGN: MSG " << m
->get_seq() << "Signature on message:" << dendl
;
179 ldout(cct
, 0) << "SIGN: MSG " << m
->get_seq() << " sig: " << m
->get_footer().sig
<< dendl
;
180 ldout(cct
, 0) << "SIGN: MSG " << m
->get_seq() << "Locally calculated signature:" << dendl
;
181 ldout(cct
, 0) << "SIGN: MSG " << m
->get_seq() << " sig_check:" << sig
<< dendl
;
183 // For the moment, printing an error message to the log and
184 // returning failure is sufficient. In the long term, we should
185 // probably have code parsing the log looking for this kind of
186 // security failure, particularly when there are large numbers of
187 // them, since the latter is a potential sign of an attack. PLR
189 ldout(cct
, 0) << "Signature failed." << dendl
;
190 return (SESSION_SIGNATURE_FAILURE
);