]>
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 | ||
27 | int CephxSessionHandler::_calc_signature(Message *m, uint64_t *psig) | |
28 | { | |
29 | const ceph_msg_header& header = m->get_header(); | |
30 | const ceph_msg_footer& footer = m->get_footer(); | |
31 | ||
28e407b8 AA |
32 | if (!HAVE_FEATURE(features, CEPHX_V2)) { |
33 | // legacy pre-mimic behavior for compatibility | |
7c673cae | 34 | |
28e407b8 AA |
35 | // optimized signature calculation |
36 | // - avoid temporary allocated buffers from encode_encrypt[_enc_bl] | |
37 | // - skip the leading 4 byte wrapper from encode_encrypt | |
38 | struct { | |
39 | __u8 v; | |
eafe8130 TL |
40 | ceph_le64 magic; |
41 | ceph_le32 len; | |
42 | ceph_le32 header_crc; | |
43 | ceph_le32 front_crc; | |
44 | ceph_le32 middle_crc; | |
45 | ceph_le32 data_crc; | |
28e407b8 | 46 | } __attribute__ ((packed)) sigblock = { |
eafe8130 TL |
47 | 1, init_le64(AUTH_ENC_MAGIC), init_le32(4*4), |
48 | init_le32(header.crc), init_le32(footer.front_crc), | |
49 | init_le32(footer.middle_crc), init_le32(footer.data_crc) | |
28e407b8 AA |
50 | }; |
51 | ||
11fdf7f2 TL |
52 | char exp_buf[CryptoKey::get_max_outbuf_size(sizeof(sigblock))]; |
53 | ||
54 | try { | |
55 | const CryptoKey::in_slice_t in { | |
56 | sizeof(sigblock), | |
57 | reinterpret_cast<const unsigned char*>(&sigblock) | |
58 | }; | |
59 | const CryptoKey::out_slice_t out { | |
60 | sizeof(exp_buf), | |
61 | reinterpret_cast<unsigned char*>(&exp_buf) | |
62 | }; | |
63 | key.encrypt(cct, in, out); | |
64 | } catch (std::exception& e) { | |
28e407b8 AA |
65 | lderr(cct) << __func__ << " failed to encrypt signature block" << dendl; |
66 | return -1; | |
67 | } | |
68 | ||
eafe8130 | 69 | *psig = *reinterpret_cast<ceph_le64*>(exp_buf); |
28e407b8 AA |
70 | } else { |
71 | // newer mimic+ signatures | |
72 | struct { | |
eafe8130 TL |
73 | ceph_le32 header_crc; |
74 | ceph_le32 front_crc; | |
75 | ceph_le32 front_len; | |
76 | ceph_le32 middle_crc; | |
77 | ceph_le32 middle_len; | |
78 | ceph_le32 data_crc; | |
79 | ceph_le32 data_len; | |
80 | ceph_le32 seq_lower_word; | |
28e407b8 | 81 | } __attribute__ ((packed)) sigblock = { |
eafe8130 TL |
82 | init_le32(header.crc), |
83 | init_le32(footer.front_crc), | |
84 | init_le32(header.front_len), | |
85 | init_le32(footer.middle_crc), | |
86 | init_le32(header.middle_len), | |
87 | init_le32(footer.data_crc), | |
88 | init_le32(header.data_len), | |
89 | init_le32(header.seq) | |
28e407b8 | 90 | }; |
7c673cae | 91 | |
11fdf7f2 TL |
92 | char exp_buf[CryptoKey::get_max_outbuf_size(sizeof(sigblock))]; |
93 | ||
94 | try { | |
95 | const CryptoKey::in_slice_t in { | |
96 | sizeof(sigblock), | |
97 | reinterpret_cast<const unsigned char*>(&sigblock) | |
98 | }; | |
99 | const CryptoKey::out_slice_t out { | |
100 | sizeof(exp_buf), | |
101 | reinterpret_cast<unsigned char*>(&exp_buf) | |
102 | }; | |
103 | key.encrypt(cct, in, out); | |
104 | } catch (std::exception& e) { | |
28e407b8 AA |
105 | lderr(cct) << __func__ << " failed to encrypt signature block" << dendl; |
106 | return -1; | |
107 | } | |
108 | ||
109 | struct enc { | |
eafe8130 | 110 | ceph_le64 a, b, c, d; |
11fdf7f2 | 111 | } *penc = reinterpret_cast<enc*>(exp_buf); |
28e407b8 AA |
112 | *psig = penc->a ^ penc->b ^ penc->c ^ penc->d; |
113 | } | |
7c673cae FG |
114 | |
115 | ldout(cct, 10) << __func__ << " seq " << m->get_seq() | |
116 | << " front_crc_ = " << footer.front_crc | |
117 | << " middle_crc = " << footer.middle_crc | |
118 | << " data_crc = " << footer.data_crc | |
119 | << " sig = " << *psig | |
120 | << dendl; | |
121 | return 0; | |
122 | } | |
123 | ||
124 | int CephxSessionHandler::sign_message(Message *m) | |
125 | { | |
126 | // If runtime signing option is off, just return success without signing. | |
127 | if (!cct->_conf->cephx_sign_messages) { | |
128 | return 0; | |
129 | } | |
130 | ||
131 | uint64_t sig; | |
132 | int r = _calc_signature(m, &sig); | |
133 | if (r < 0) | |
134 | return r; | |
135 | ||
136 | ceph_msg_footer& f = m->get_footer(); | |
137 | f.sig = sig; | |
138 | f.flags = (unsigned)f.flags | CEPH_MSG_FOOTER_SIGNED; | |
7c673cae FG |
139 | ldout(cct, 20) << "Putting signature in client message(seq # " << m->get_seq() |
140 | << "): sig = " << sig << dendl; | |
141 | return 0; | |
142 | } | |
143 | ||
144 | int CephxSessionHandler::check_message_signature(Message *m) | |
145 | { | |
146 | // If runtime signing option is off, just return success without checking signature. | |
147 | if (!cct->_conf->cephx_sign_messages) { | |
148 | return 0; | |
149 | } | |
150 | if ((features & CEPH_FEATURE_MSG_AUTH) == 0) { | |
151 | // it's fine, we didn't negotiate this feature. | |
152 | return 0; | |
153 | } | |
154 | ||
155 | uint64_t sig; | |
156 | int r = _calc_signature(m, &sig); | |
157 | if (r < 0) | |
158 | return r; | |
159 | ||
7c673cae FG |
160 | if (sig != m->get_footer().sig) { |
161 | // Should have been signed, but signature check failed. PLR | |
162 | if (!(m->get_footer().flags & CEPH_MSG_FOOTER_SIGNED)) { | |
163 | ldout(cct, 0) << "SIGN: MSG " << m->get_seq() << " Sender did not set CEPH_MSG_FOOTER_SIGNED." << dendl; | |
164 | } | |
165 | ldout(cct, 0) << "SIGN: MSG " << m->get_seq() << " Message signature does not match contents." << dendl; | |
166 | ldout(cct, 0) << "SIGN: MSG " << m->get_seq() << "Signature on message:" << dendl; | |
167 | ldout(cct, 0) << "SIGN: MSG " << m->get_seq() << " sig: " << m->get_footer().sig << dendl; | |
168 | ldout(cct, 0) << "SIGN: MSG " << m->get_seq() << "Locally calculated signature:" << dendl; | |
169 | ldout(cct, 0) << "SIGN: MSG " << m->get_seq() << " sig_check:" << sig << dendl; | |
170 | ||
171 | // For the moment, printing an error message to the log and | |
172 | // returning failure is sufficient. In the long term, we should | |
173 | // probably have code parsing the log looking for this kind of | |
174 | // security failure, particularly when there are large numbers of | |
175 | // them, since the latter is a potential sign of an attack. PLR | |
176 | ||
7c673cae FG |
177 | ldout(cct, 0) << "Signature failed." << dendl; |
178 | return (SESSION_SIGNATURE_FAILURE); | |
179 | } | |
180 | ||
7c673cae FG |
181 | return 0; |
182 | } |