]>
Commit | Line | Data |
---|---|---|
7c673cae FG |
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 | 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; | |
40 | __le64 magic; | |
41 | __le32 len; | |
42 | __le32 header_crc; | |
43 | __le32 front_crc; | |
44 | __le32 middle_crc; | |
45 | __le32 data_crc; | |
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) | |
50 | }; | |
51 | ||
52 | bufferlist bl_plaintext; | |
53 | bl_plaintext.append(buffer::create_static(sizeof(sigblock), | |
54 | (char*)&sigblock)); | |
55 | ||
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; | |
59 | return -1; | |
60 | } | |
61 | ||
62 | bufferlist::iterator ci = bl_ciphertext.begin(); | |
63 | ::decode(*psig, ci); | |
64 | } else { | |
65 | // newer mimic+ signatures | |
66 | struct { | |
67 | __le32 header_crc; | |
68 | __le32 front_crc; | |
69 | __le32 front_len; | |
70 | __le32 middle_crc; | |
71 | __le32 middle_len; | |
72 | __le32 data_crc; | |
73 | __le32 data_len; | |
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) | |
84 | }; | |
7c673cae | 85 | |
28e407b8 AA |
86 | bufferlist bl_plaintext; |
87 | bl_plaintext.append(buffer::create_static(sizeof(sigblock), | |
88 | (char*)&sigblock)); | |
89 | ||
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; | |
93 | return -1; | |
94 | } | |
95 | ||
96 | struct enc { | |
97 | __le64 a, b, c, d; | |
98 | } *penc = reinterpret_cast<enc*>(bl_ciphertext.c_str()); | |
99 | *psig = penc->a ^ penc->b ^ penc->c ^ penc->d; | |
100 | } | |
7c673cae FG |
101 | |
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 | |
107 | << dendl; | |
108 | return 0; | |
109 | } | |
110 | ||
111 | int CephxSessionHandler::sign_message(Message *m) | |
112 | { | |
113 | // If runtime signing option is off, just return success without signing. | |
114 | if (!cct->_conf->cephx_sign_messages) { | |
115 | return 0; | |
116 | } | |
117 | ||
118 | uint64_t sig; | |
119 | int r = _calc_signature(m, &sig); | |
120 | if (r < 0) | |
121 | return r; | |
122 | ||
123 | ceph_msg_footer& f = m->get_footer(); | |
124 | f.sig = sig; | |
125 | f.flags = (unsigned)f.flags | CEPH_MSG_FOOTER_SIGNED; | |
7c673cae FG |
126 | ldout(cct, 20) << "Putting signature in client message(seq # " << m->get_seq() |
127 | << "): sig = " << sig << dendl; | |
128 | return 0; | |
129 | } | |
130 | ||
131 | int CephxSessionHandler::check_message_signature(Message *m) | |
132 | { | |
133 | // If runtime signing option is off, just return success without checking signature. | |
134 | if (!cct->_conf->cephx_sign_messages) { | |
135 | return 0; | |
136 | } | |
137 | if ((features & CEPH_FEATURE_MSG_AUTH) == 0) { | |
138 | // it's fine, we didn't negotiate this feature. | |
139 | return 0; | |
140 | } | |
141 | ||
142 | uint64_t sig; | |
143 | int r = _calc_signature(m, &sig); | |
144 | if (r < 0) | |
145 | return r; | |
146 | ||
7c673cae FG |
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; | |
151 | } | |
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; | |
157 | ||
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 | |
163 | ||
7c673cae FG |
164 | ldout(cct, 0) << "Signature failed." << dendl; |
165 | return (SESSION_SIGNATURE_FAILURE); | |
166 | } | |
167 | ||
7c673cae FG |
168 | return 0; |
169 | } | |
170 |