]>
Commit | Line | Data |
---|---|---|
11fdf7f2 | 1 | // -*- mode:C++; tab-width:8; c-basic-offset:2; indent-tabs-mode:t -*- |
7c673cae FG |
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 | |
11fdf7f2 | 10 | * License version 2.1, as published by the Free Software |
7c673cae | 11 | * Foundation. See file COPYING. |
11fdf7f2 | 12 | * |
7c673cae FG |
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" | |
11fdf7f2 | 24 | |
7c673cae FG |
25 | #define dout_subsys ceph_subsys_auth |
26 | ||
9f95a23c TL |
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 | ||
7c673cae FG |
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 | ||
28e407b8 AA |
44 | if (!HAVE_FEATURE(features, CEPHX_V2)) { |
45 | // legacy pre-mimic behavior for compatibility | |
7c673cae | 46 | |
28e407b8 AA |
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; | |
eafe8130 TL |
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; | |
28e407b8 | 58 | } __attribute__ ((packed)) sigblock = { |
20effc67 TL |
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) | |
28e407b8 AA |
62 | }; |
63 | ||
11fdf7f2 TL |
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) { | |
28e407b8 AA |
77 | lderr(cct) << __func__ << " failed to encrypt signature block" << dendl; |
78 | return -1; | |
79 | } | |
80 | ||
eafe8130 | 81 | *psig = *reinterpret_cast<ceph_le64*>(exp_buf); |
28e407b8 AA |
82 | } else { |
83 | // newer mimic+ signatures | |
84 | struct { | |
eafe8130 TL |
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; | |
28e407b8 | 93 | } __attribute__ ((packed)) sigblock = { |
20effc67 TL |
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) | |
28e407b8 | 102 | }; |
7c673cae | 103 | |
11fdf7f2 TL |
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) { | |
28e407b8 AA |
117 | lderr(cct) << __func__ << " failed to encrypt signature block" << dendl; |
118 | return -1; | |
119 | } | |
120 | ||
121 | struct enc { | |
eafe8130 | 122 | ceph_le64 a, b, c, d; |
11fdf7f2 | 123 | } *penc = reinterpret_cast<enc*>(exp_buf); |
28e407b8 AA |
124 | *psig = penc->a ^ penc->b ^ penc->c ^ penc->d; |
125 | } | |
7c673cae FG |
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. | |
9f95a23c | 139 | if (!conf(cct)->cephx_sign_messages) { |
7c673cae FG |
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; | |
7c673cae FG |
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. | |
9f95a23c | 159 | if (!conf(cct)->cephx_sign_messages) { |
7c673cae FG |
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 | ||
7c673cae FG |
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 | ||
7c673cae FG |
189 | ldout(cct, 0) << "Signature failed." << dendl; |
190 | return (SESSION_SIGNATURE_FAILURE); | |
191 | } | |
192 | ||
7c673cae FG |
193 | return 0; |
194 | } |