]> git.proxmox.com Git - ceph.git/blob - ceph/src/auth/cephx/CephxSessionHandler.cc
bump version to 18.2.2-pve1
[ceph.git] / ceph / src / auth / cephx / CephxSessionHandler.cc
1 // -*- mode:C++; tab-width:8; c-basic-offset:2; indent-tabs-mode:t -*-
2 // vim: ts=8 sw=2 smarttab
3 /*
4 * Ceph - scalable distributed file system
5 *
6 * Copyright (C) 2004-2009 Sage Weil <sage@newdream.net>
7 *
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.
12 *
13 */
14
15 #include "CephxSessionHandler.h"
16 #include "CephxProtocol.h"
17
18 #include <errno.h>
19 #include <sstream>
20
21 #include "common/config.h"
22 #include "include/ceph_features.h"
23 #include "msg/Message.h"
24
25 #define dout_subsys ceph_subsys_auth
26
27 namespace {
28 #ifdef WITH_SEASTAR
29 crimson::common::ConfigProxy& conf(CephContext*) {
30 return crimson::common::local_conf();
31 }
32 #else
33 ConfigProxy& conf(CephContext* cct) {
34 return cct->_conf;
35 }
36 #endif
37 }
38
39 int CephxSessionHandler::_calc_signature(Message *m, uint64_t *psig)
40 {
41 const ceph_msg_header& header = m->get_header();
42 const ceph_msg_footer& footer = m->get_footer();
43
44 if (!HAVE_FEATURE(features, CEPHX_V2)) {
45 // legacy pre-mimic behavior for compatibility
46
47 // optimized signature calculation
48 // - avoid temporary allocated buffers from encode_encrypt[_enc_bl]
49 // - skip the leading 4 byte wrapper from encode_encrypt
50 struct {
51 __u8 v;
52 ceph_le64 magic;
53 ceph_le32 len;
54 ceph_le32 header_crc;
55 ceph_le32 front_crc;
56 ceph_le32 middle_crc;
57 ceph_le32 data_crc;
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)
62 };
63
64 char exp_buf[CryptoKey::get_max_outbuf_size(sizeof(sigblock))];
65
66 try {
67 const CryptoKey::in_slice_t in {
68 sizeof(sigblock),
69 reinterpret_cast<const unsigned char*>(&sigblock)
70 };
71 const CryptoKey::out_slice_t out {
72 sizeof(exp_buf),
73 reinterpret_cast<unsigned char*>(&exp_buf)
74 };
75 key.encrypt(cct, in, out);
76 } catch (std::exception& e) {
77 lderr(cct) << __func__ << " failed to encrypt signature block" << dendl;
78 return -1;
79 }
80
81 *psig = *reinterpret_cast<ceph_le64*>(exp_buf);
82 } else {
83 // newer mimic+ signatures
84 struct {
85 ceph_le32 header_crc;
86 ceph_le32 front_crc;
87 ceph_le32 front_len;
88 ceph_le32 middle_crc;
89 ceph_le32 middle_len;
90 ceph_le32 data_crc;
91 ceph_le32 data_len;
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)
102 };
103
104 char exp_buf[CryptoKey::get_max_outbuf_size(sizeof(sigblock))];
105
106 try {
107 const CryptoKey::in_slice_t in {
108 sizeof(sigblock),
109 reinterpret_cast<const unsigned char*>(&sigblock)
110 };
111 const CryptoKey::out_slice_t out {
112 sizeof(exp_buf),
113 reinterpret_cast<unsigned char*>(&exp_buf)
114 };
115 key.encrypt(cct, in, out);
116 } catch (std::exception& e) {
117 lderr(cct) << __func__ << " failed to encrypt signature block" << dendl;
118 return -1;
119 }
120
121 struct enc {
122 ceph_le64 a, b, c, d;
123 } *penc = reinterpret_cast<enc*>(exp_buf);
124 *psig = penc->a ^ penc->b ^ penc->c ^ penc->d;
125 }
126
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
132 << dendl;
133 return 0;
134 }
135
136 int CephxSessionHandler::sign_message(Message *m)
137 {
138 // If runtime signing option is off, just return success without signing.
139 if (!conf(cct)->cephx_sign_messages) {
140 return 0;
141 }
142
143 uint64_t sig;
144 int r = _calc_signature(m, &sig);
145 if (r < 0)
146 return r;
147
148 ceph_msg_footer& f = m->get_footer();
149 f.sig = sig;
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;
153 return 0;
154 }
155
156 int CephxSessionHandler::check_message_signature(Message *m)
157 {
158 // If runtime signing option is off, just return success without checking signature.
159 if (!conf(cct)->cephx_sign_messages) {
160 return 0;
161 }
162 if ((features & CEPH_FEATURE_MSG_AUTH) == 0) {
163 // it's fine, we didn't negotiate this feature.
164 return 0;
165 }
166
167 uint64_t sig;
168 int r = _calc_signature(m, &sig);
169 if (r < 0)
170 return r;
171
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;
176 }
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;
182
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
188
189 ldout(cct, 0) << "Signature failed." << dendl;
190 return (SESSION_SIGNATURE_FAILURE);
191 }
192
193 return 0;
194 }