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
27 int CephxSessionHandler::_calc_signature(Message
*m
, uint64_t *psig
)
29 const ceph_msg_header
& header
= m
->get_header();
30 const ceph_msg_footer
& footer
= m
->get_footer();
32 if (!HAVE_FEATURE(features
, CEPHX_V2
)) {
33 // legacy pre-mimic behavior for compatibility
35 // optimized signature calculation
36 // - avoid temporary allocated buffers from encode_encrypt[_enc_bl]
37 // - skip the leading 4 byte wrapper from encode_encrypt
46 } __attribute__ ((packed
)) sigblock
= {
47 1, mswab(AUTH_ENC_MAGIC
), mswab
<uint32_t>(4*4),
48 mswab
<uint32_t>(header
.crc
), mswab
<uint32_t>(footer
.front_crc
),
49 mswab
<uint32_t>(footer
.middle_crc
), mswab
<uint32_t>(footer
.data_crc
)
52 bufferlist bl_plaintext
;
53 bl_plaintext
.append(buffer::create_static(sizeof(sigblock
),
56 bufferlist bl_ciphertext
;
57 if (key
.encrypt(cct
, bl_plaintext
, bl_ciphertext
, NULL
) < 0) {
58 lderr(cct
) << __func__
<< " failed to encrypt signature block" << dendl
;
62 bufferlist::iterator ci
= bl_ciphertext
.begin();
65 // newer mimic+ signatures
74 __le32 seq_lower_word
;
75 } __attribute__ ((packed
)) sigblock
= {
76 mswab
<uint32_t>(header
.crc
),
77 mswab
<uint32_t>(footer
.front_crc
),
78 mswab
<uint32_t>(header
.front_len
),
79 mswab
<uint32_t>(footer
.middle_crc
),
80 mswab
<uint32_t>(header
.middle_len
),
81 mswab
<uint32_t>(footer
.data_crc
),
82 mswab
<uint32_t>(header
.data_len
),
83 mswab
<uint32_t>(header
.seq
)
86 bufferlist bl_plaintext
;
87 bl_plaintext
.append(buffer::create_static(sizeof(sigblock
),
90 bufferlist bl_ciphertext
;
91 if (key
.encrypt(cct
, bl_plaintext
, bl_ciphertext
, NULL
) < 0) {
92 lderr(cct
) << __func__
<< " failed to encrypt signature block" << dendl
;
98 } *penc
= reinterpret_cast<enc
*>(bl_ciphertext
.c_str());
99 *psig
= penc
->a
^ penc
->b
^ penc
->c
^ penc
->d
;
102 ldout(cct
, 10) << __func__
<< " seq " << m
->get_seq()
103 << " front_crc_ = " << footer
.front_crc
104 << " middle_crc = " << footer
.middle_crc
105 << " data_crc = " << footer
.data_crc
106 << " sig = " << *psig
111 int CephxSessionHandler::sign_message(Message
*m
)
113 // If runtime signing option is off, just return success without signing.
114 if (!cct
->_conf
->cephx_sign_messages
) {
119 int r
= _calc_signature(m
, &sig
);
123 ceph_msg_footer
& f
= m
->get_footer();
125 f
.flags
= (unsigned)f
.flags
| CEPH_MSG_FOOTER_SIGNED
;
126 ldout(cct
, 20) << "Putting signature in client message(seq # " << m
->get_seq()
127 << "): sig = " << sig
<< dendl
;
131 int CephxSessionHandler::check_message_signature(Message
*m
)
133 // If runtime signing option is off, just return success without checking signature.
134 if (!cct
->_conf
->cephx_sign_messages
) {
137 if ((features
& CEPH_FEATURE_MSG_AUTH
) == 0) {
138 // it's fine, we didn't negotiate this feature.
143 int r
= _calc_signature(m
, &sig
);
147 if (sig
!= m
->get_footer().sig
) {
148 // Should have been signed, but signature check failed. PLR
149 if (!(m
->get_footer().flags
& CEPH_MSG_FOOTER_SIGNED
)) {
150 ldout(cct
, 0) << "SIGN: MSG " << m
->get_seq() << " Sender did not set CEPH_MSG_FOOTER_SIGNED." << dendl
;
152 ldout(cct
, 0) << "SIGN: MSG " << m
->get_seq() << " Message signature does not match contents." << dendl
;
153 ldout(cct
, 0) << "SIGN: MSG " << m
->get_seq() << "Signature on message:" << dendl
;
154 ldout(cct
, 0) << "SIGN: MSG " << m
->get_seq() << " sig: " << m
->get_footer().sig
<< dendl
;
155 ldout(cct
, 0) << "SIGN: MSG " << m
->get_seq() << "Locally calculated signature:" << dendl
;
156 ldout(cct
, 0) << "SIGN: MSG " << m
->get_seq() << " sig_check:" << sig
<< dendl
;
158 // For the moment, printing an error message to the log and
159 // returning failure is sufficient. In the long term, we should
160 // probably have code parsing the log looking for this kind of
161 // security failure, particularly when there are large numbers of
162 // them, since the latter is a potential sign of an attack. PLR
164 ldout(cct
, 0) << "Signature failed." << dendl
;
165 return (SESSION_SIGNATURE_FAILURE
);