]>
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) 2009-2011 New Dream Network | |
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 "CephxProtocol.h" | |
16 | #include "common/Clock.h" | |
11fdf7f2 | 17 | #include "common/ceph_context.h" |
7c673cae FG |
18 | #include "common/config.h" |
19 | #include "common/debug.h" | |
20 | #include "include/buffer.h" | |
21 | ||
22 | #define dout_subsys ceph_subsys_auth | |
23 | #undef dout_prefix | |
24 | #define dout_prefix *_dout << "cephx: " | |
25 | ||
f67539c2 TL |
26 | using std::dec; |
27 | using std::hex; | |
28 | using std::vector; | |
7c673cae | 29 | |
f67539c2 TL |
30 | using ceph::bufferlist; |
31 | using ceph::decode; | |
32 | using ceph::encode; | |
7c673cae FG |
33 | |
34 | void cephx_calc_client_server_challenge(CephContext *cct, CryptoKey& secret, uint64_t server_challenge, | |
35 | uint64_t client_challenge, uint64_t *key, std::string &error) | |
36 | { | |
37 | CephXChallengeBlob b; | |
38 | b.server_challenge = server_challenge; | |
39 | b.client_challenge = client_challenge; | |
40 | ||
41 | bufferlist enc; | |
42 | if (encode_encrypt(cct, b, secret, enc, error)) | |
43 | return; | |
44 | ||
45 | uint64_t k = 0; | |
eafe8130 | 46 | const ceph_le64 *p = (const ceph_le64 *)enc.c_str(); |
7c673cae | 47 | for (int pos = 0; pos + sizeof(k) <= enc.length(); pos+=sizeof(k), p++) |
eafe8130 | 48 | k ^= *p; |
7c673cae FG |
49 | *key = k; |
50 | } | |
51 | ||
52 | ||
53 | /* | |
54 | * Authentication | |
55 | */ | |
56 | ||
57 | bool cephx_build_service_ticket_blob(CephContext *cct, CephXSessionAuthInfo& info, | |
58 | CephXTicketBlob& blob) | |
59 | { | |
60 | CephXServiceTicketInfo ticket_info; | |
61 | ticket_info.session_key = info.session_key; | |
62 | ticket_info.ticket = info.ticket; | |
63 | ticket_info.ticket.caps = info.ticket.caps; | |
64 | ||
11fdf7f2 TL |
65 | ldout(cct, 10) << "build_service_ticket service " |
66 | << ceph_entity_type_name(info.service_id) | |
67 | << " secret_id " << info.secret_id | |
68 | << " ticket_info.ticket.name=" | |
69 | << ticket_info.ticket.name.to_str() | |
70 | << " ticket.global_id " << info.ticket.global_id << dendl; | |
7c673cae FG |
71 | blob.secret_id = info.secret_id; |
72 | std::string error; | |
73 | if (!info.service_secret.get_secret().length()) | |
74 | error = "invalid key"; // Bad key? | |
75 | else | |
76 | encode_encrypt_enc_bl(cct, ticket_info, info.service_secret, blob.blob, error); | |
77 | if (!error.empty()) { | |
78 | ldout(cct, -1) << "cephx_build_service_ticket_blob failed with error " | |
79 | << error << dendl; | |
80 | return false; | |
81 | } | |
82 | return true; | |
83 | } | |
84 | ||
85 | /* | |
86 | * AUTH SERVER: authenticate | |
87 | * | |
88 | * Authenticate principal, respond with AuthServiceTicketInfo | |
89 | * | |
90 | * {session key, validity}^principal_secret | |
91 | * {principal_ticket, session key}^service_secret ... "enc_ticket" | |
92 | */ | |
93 | bool cephx_build_service_ticket_reply(CephContext *cct, | |
94 | CryptoKey& principal_secret, | |
95 | vector<CephXSessionAuthInfo> ticket_info_vec, | |
96 | bool should_encrypt_ticket, | |
97 | CryptoKey& ticket_enc_key, | |
98 | bufferlist& reply) | |
99 | { | |
100 | __u8 service_ticket_reply_v = 1; | |
f67539c2 | 101 | using ceph::encode; |
11fdf7f2 | 102 | encode(service_ticket_reply_v, reply); |
7c673cae FG |
103 | |
104 | uint32_t num = ticket_info_vec.size(); | |
11fdf7f2 | 105 | encode(num, reply); |
7c673cae FG |
106 | ldout(cct, 10) << "build_service_ticket_reply encoding " << num |
107 | << " tickets with secret " << principal_secret << dendl; | |
108 | ||
f67539c2 | 109 | for (auto ticket_iter = ticket_info_vec.begin(); |
7c673cae FG |
110 | ticket_iter != ticket_info_vec.end(); |
111 | ++ticket_iter) { | |
112 | CephXSessionAuthInfo& info = *ticket_iter; | |
11fdf7f2 | 113 | encode(info.service_id, reply); |
7c673cae FG |
114 | |
115 | __u8 service_ticket_v = 1; | |
11fdf7f2 | 116 | encode(service_ticket_v, reply); |
7c673cae FG |
117 | |
118 | CephXServiceTicket msg_a; | |
119 | msg_a.session_key = info.session_key; | |
120 | msg_a.validity = info.validity; | |
121 | std::string error; | |
122 | if (encode_encrypt(cct, msg_a, principal_secret, reply, error)) { | |
123 | ldout(cct, -1) << "error encoding encrypted: " << error << dendl; | |
124 | return false; | |
125 | } | |
126 | ||
127 | bufferlist service_ticket_bl; | |
128 | CephXTicketBlob blob; | |
129 | if (!cephx_build_service_ticket_blob(cct, info, blob)) { | |
130 | return false; | |
131 | } | |
11fdf7f2 | 132 | encode(blob, service_ticket_bl); |
7c673cae FG |
133 | |
134 | ldout(cct, 30) << "service_ticket_blob is "; | |
135 | service_ticket_bl.hexdump(*_dout); | |
136 | *_dout << dendl; | |
137 | ||
11fdf7f2 | 138 | encode((__u8)should_encrypt_ticket, reply); |
7c673cae FG |
139 | if (should_encrypt_ticket) { |
140 | if (encode_encrypt(cct, service_ticket_bl, ticket_enc_key, reply, error)) { | |
141 | ldout(cct, -1) << "error encoding encrypted ticket: " << error << dendl; | |
142 | return false; | |
143 | } | |
144 | } else { | |
11fdf7f2 | 145 | encode(service_ticket_bl, reply); |
7c673cae FG |
146 | } |
147 | } | |
148 | return true; | |
149 | } | |
150 | ||
151 | /* | |
152 | * PRINCIPAL: verify our attempt to authenticate succeeded. fill out | |
153 | * this ServiceTicket with the result. | |
154 | */ | |
11fdf7f2 TL |
155 | bool CephXTicketHandler::verify_service_ticket_reply( |
156 | CryptoKey& secret, | |
157 | bufferlist::const_iterator& indata) | |
7c673cae | 158 | { |
f67539c2 | 159 | using ceph::decode; |
eafe8130 TL |
160 | try { |
161 | __u8 service_ticket_v; | |
162 | decode(service_ticket_v, indata); | |
7c673cae | 163 | |
eafe8130 | 164 | CephXServiceTicket msg_a; |
7c673cae | 165 | std::string error; |
eafe8130 TL |
166 | if (decode_decrypt(cct, msg_a, secret, indata, error)) { |
167 | ldout(cct, 0) << __func__ << " failed decode_decrypt, error is: " << error | |
168 | << dendl; | |
7c673cae FG |
169 | return false; |
170 | } | |
7c673cae | 171 | |
eafe8130 TL |
172 | __u8 ticket_enc; |
173 | decode(ticket_enc, indata); | |
174 | ||
175 | bufferlist service_ticket_bl; | |
176 | if (ticket_enc) { | |
177 | ldout(cct, 10) << __func__ << " got encrypted ticket" << dendl; | |
178 | std::string error; | |
179 | if (decode_decrypt(cct, service_ticket_bl, session_key, indata, error)) { | |
180 | ldout(cct, 10) << __func__ << " decode_decrypt failed " | |
181 | << "with " << error << dendl; | |
182 | return false; | |
183 | } | |
184 | } else { | |
185 | decode(service_ticket_bl, indata); | |
186 | } | |
187 | auto iter = service_ticket_bl.cbegin(); | |
188 | decode(ticket, iter); | |
189 | ldout(cct, 10) << __func__ << " ticket.secret_id=" << ticket.secret_id | |
190 | << dendl; | |
191 | ||
192 | ldout(cct, 10) << __func__ << " service " | |
193 | << ceph_entity_type_name(service_id) | |
194 | << " secret_id " << ticket.secret_id | |
195 | << " session_key " << msg_a.session_key | |
196 | << " validity=" << msg_a.validity << dendl; | |
197 | session_key = msg_a.session_key; | |
198 | if (!msg_a.validity.is_zero()) { | |
199 | expires = ceph_clock_now(); | |
200 | expires += msg_a.validity; | |
201 | renew_after = expires; | |
202 | renew_after -= ((double)msg_a.validity.sec() / 4); | |
203 | ldout(cct, 10) << __func__ << " ticket expires=" << expires | |
204 | << " renew_after=" << renew_after << dendl; | |
205 | } | |
206 | ||
207 | have_key_flag = true; | |
208 | return true; | |
f67539c2 | 209 | } catch (ceph::buffer::error& e) { |
eafe8130 TL |
210 | ldout(cct, 1) << __func__ << " decode error: " << e.what() << dendl; |
211 | return false; | |
212 | } | |
7c673cae FG |
213 | } |
214 | ||
215 | bool CephXTicketHandler::have_key() | |
216 | { | |
217 | if (have_key_flag) { | |
218 | have_key_flag = ceph_clock_now() < expires; | |
219 | } | |
220 | ||
221 | return have_key_flag; | |
222 | } | |
223 | ||
224 | bool CephXTicketHandler::need_key() const | |
225 | { | |
226 | if (have_key_flag) { | |
227 | return (!expires.is_zero()) && (ceph_clock_now() >= renew_after); | |
228 | } | |
229 | ||
230 | return true; | |
231 | } | |
232 | ||
233 | bool CephXTicketManager::have_key(uint32_t service_id) | |
234 | { | |
f67539c2 | 235 | auto iter = tickets_map.find(service_id); |
7c673cae FG |
236 | if (iter == tickets_map.end()) |
237 | return false; | |
238 | return iter->second.have_key(); | |
239 | } | |
240 | ||
241 | bool CephXTicketManager::need_key(uint32_t service_id) const | |
242 | { | |
f67539c2 | 243 | auto iter = tickets_map.find(service_id); |
7c673cae FG |
244 | if (iter == tickets_map.end()) |
245 | return true; | |
246 | return iter->second.need_key(); | |
247 | } | |
248 | ||
249 | void CephXTicketManager::set_have_need_key(uint32_t service_id, uint32_t& have, uint32_t& need) | |
250 | { | |
f67539c2 | 251 | auto iter = tickets_map.find(service_id); |
7c673cae FG |
252 | if (iter == tickets_map.end()) { |
253 | have &= ~service_id; | |
254 | need |= service_id; | |
255 | ldout(cct, 10) << "set_have_need_key no handler for service " | |
256 | << ceph_entity_type_name(service_id) << dendl; | |
257 | return; | |
258 | } | |
259 | ||
260 | //ldout(cct, 10) << "set_have_need_key service " << ceph_entity_type_name(service_id) | |
261 | //<< " (" << service_id << ")" | |
262 | //<< " need=" << iter->second.need_key() << " have=" << iter->second.have_key() << dendl; | |
263 | if (iter->second.need_key()) | |
264 | need |= service_id; | |
265 | else | |
266 | need &= ~service_id; | |
267 | ||
268 | if (iter->second.have_key()) | |
269 | have |= service_id; | |
270 | else | |
271 | have &= ~service_id; | |
272 | } | |
273 | ||
274 | void CephXTicketManager::invalidate_ticket(uint32_t service_id) | |
275 | { | |
f67539c2 | 276 | auto iter = tickets_map.find(service_id); |
7c673cae FG |
277 | if (iter != tickets_map.end()) |
278 | iter->second.invalidate_ticket(); | |
279 | } | |
280 | ||
281 | /* | |
282 | * PRINCIPAL: verify our attempt to authenticate succeeded. fill out | |
283 | * this ServiceTicket with the result. | |
284 | */ | |
285 | bool CephXTicketManager::verify_service_ticket_reply(CryptoKey& secret, | |
11fdf7f2 | 286 | bufferlist::const_iterator& indata) |
7c673cae FG |
287 | { |
288 | __u8 service_ticket_reply_v; | |
9f95a23c | 289 | uint32_t num = 0; |
eafe8130 TL |
290 | try { |
291 | decode(service_ticket_reply_v, indata); | |
292 | decode(num, indata); | |
f67539c2 | 293 | } catch (ceph::buffer::error& e) { |
eafe8130 TL |
294 | ldout(cct, 10) << __func__ << " failed to decode ticket v or count: " |
295 | << e.what() << dendl; | |
296 | } | |
7c673cae FG |
297 | ldout(cct, 10) << "verify_service_ticket_reply got " << num << " keys" << dendl; |
298 | ||
299 | for (int i=0; i<(int)num; i++) { | |
9f95a23c | 300 | uint32_t type = 0; |
eafe8130 TL |
301 | try { |
302 | decode(type, indata); | |
f67539c2 | 303 | } catch (ceph::buffer::error& e) { |
eafe8130 TL |
304 | ldout(cct, 10) << __func__ << " failed to decode ticket type: " << e.what() |
305 | << dendl; | |
306 | } | |
7c673cae FG |
307 | ldout(cct, 10) << "got key for service_id " << ceph_entity_type_name(type) << dendl; |
308 | CephXTicketHandler& handler = get_handler(type); | |
309 | if (!handler.verify_service_ticket_reply(secret, indata)) { | |
310 | return false; | |
311 | } | |
312 | handler.service_id = type; | |
313 | } | |
314 | ||
7c673cae FG |
315 | return true; |
316 | } | |
317 | ||
318 | /* | |
319 | * PRINCIPAL: build authorizer to access the service. | |
320 | * | |
321 | * ticket, {timestamp}^session_key | |
322 | */ | |
323 | CephXAuthorizer *CephXTicketHandler::build_authorizer(uint64_t global_id) const | |
324 | { | |
325 | CephXAuthorizer *a = new CephXAuthorizer(cct); | |
326 | a->session_key = session_key; | |
11fdf7f2 | 327 | cct->random()->get_bytes((char*)&a->nonce, sizeof(a->nonce)); |
7c673cae | 328 | |
11fdf7f2 TL |
329 | __u8 authorizer_v = 1; // see AUTH_MODE_* in Auth.h |
330 | encode(authorizer_v, a->bl); | |
331 | encode(global_id, a->bl); | |
332 | encode(service_id, a->bl); | |
7c673cae | 333 | |
11fdf7f2 | 334 | encode(ticket, a->bl); |
28e407b8 | 335 | a->base_bl = a->bl; |
7c673cae FG |
336 | |
337 | CephXAuthorize msg; | |
338 | msg.nonce = a->nonce; | |
339 | ||
340 | std::string error; | |
341 | if (encode_encrypt(cct, msg, session_key, a->bl, error)) { | |
342 | ldout(cct, 0) << "failed to encrypt authorizer: " << error << dendl; | |
343 | delete a; | |
344 | return 0; | |
345 | } | |
346 | return a; | |
347 | } | |
348 | ||
349 | /* | |
350 | * PRINCIPAL: build authorizer to access the service. | |
351 | * | |
352 | * ticket, {timestamp}^session_key | |
353 | */ | |
354 | CephXAuthorizer *CephXTicketManager::build_authorizer(uint32_t service_id) const | |
355 | { | |
f67539c2 | 356 | auto iter = tickets_map.find(service_id); |
7c673cae FG |
357 | if (iter == tickets_map.end()) { |
358 | ldout(cct, 0) << "no TicketHandler for service " | |
359 | << ceph_entity_type_name(service_id) << dendl; | |
360 | return NULL; | |
361 | } | |
362 | ||
363 | const CephXTicketHandler& handler = iter->second; | |
364 | return handler.build_authorizer(global_id); | |
365 | } | |
366 | ||
367 | void CephXTicketManager::validate_tickets(uint32_t mask, uint32_t& have, uint32_t& need) | |
368 | { | |
369 | uint32_t i; | |
370 | need = 0; | |
371 | for (i = 1; i<=mask; i<<=1) { | |
372 | if (mask & i) { | |
373 | set_have_need_key(i, have, need); | |
374 | } | |
375 | } | |
376 | ldout(cct, 10) << "validate_tickets want " << mask << " have " << have | |
377 | << " need " << need << dendl; | |
378 | } | |
379 | ||
c5c27e9a TL |
380 | bool cephx_decode_ticket(CephContext *cct, KeyStore *keys, |
381 | uint32_t service_id, | |
382 | const CephXTicketBlob& ticket_blob, | |
383 | CephXServiceTicketInfo& ticket_info) | |
7c673cae FG |
384 | { |
385 | uint64_t secret_id = ticket_blob.secret_id; | |
386 | CryptoKey service_secret; | |
387 | ||
388 | if (!ticket_blob.blob.length()) { | |
389 | return false; | |
390 | } | |
391 | ||
392 | if (secret_id == (uint64_t)-1) { | |
393 | if (!keys->get_secret(cct->_conf->name, service_secret)) { | |
394 | ldout(cct, 0) << "ceph_decode_ticket could not get general service secret for service_id=" | |
395 | << ceph_entity_type_name(service_id) << " secret_id=" << secret_id << dendl; | |
396 | return false; | |
397 | } | |
398 | } else { | |
399 | if (!keys->get_service_secret(service_id, secret_id, service_secret)) { | |
400 | ldout(cct, 0) << "ceph_decode_ticket could not get service secret for service_id=" | |
401 | << ceph_entity_type_name(service_id) << " secret_id=" << secret_id << dendl; | |
402 | return false; | |
403 | } | |
404 | } | |
405 | ||
406 | std::string error; | |
407 | decode_decrypt_enc_bl(cct, ticket_info, service_secret, ticket_blob.blob, error); | |
408 | if (!error.empty()) { | |
409 | ldout(cct, 0) << "ceph_decode_ticket could not decrypt ticket info. error:" | |
410 | << error << dendl; | |
411 | return false; | |
412 | } | |
413 | ||
414 | return true; | |
415 | } | |
416 | ||
417 | /* | |
418 | * SERVICE: verify authorizer and generate reply authorizer | |
419 | * | |
420 | * {timestamp + 1}^session_key | |
421 | */ | |
9f95a23c | 422 | bool cephx_verify_authorizer(CephContext *cct, const KeyStore& keys, |
11fdf7f2 TL |
423 | bufferlist::const_iterator& indata, |
424 | size_t connection_secret_required_len, | |
28e407b8 AA |
425 | CephXServiceTicketInfo& ticket_info, |
426 | std::unique_ptr<AuthAuthorizerChallenge> *challenge, | |
11fdf7f2 TL |
427 | std::string *connection_secret, |
428 | bufferlist *reply_bl) | |
7c673cae FG |
429 | { |
430 | __u8 authorizer_v; | |
431 | uint32_t service_id; | |
432 | uint64_t global_id; | |
433 | CryptoKey service_secret; | |
434 | // ticket blob | |
435 | CephXTicketBlob ticket; | |
436 | ||
7c673cae | 437 | try { |
11fdf7f2 TL |
438 | decode(authorizer_v, indata); |
439 | decode(global_id, indata); | |
440 | decode(service_id, indata); | |
441 | decode(ticket, indata); | |
f67539c2 | 442 | } catch (ceph::buffer::end_of_buffer &e) { |
7c673cae FG |
443 | // Unable to decode! |
444 | return false; | |
445 | } | |
446 | ldout(cct, 10) << "verify_authorizer decrypted service " | |
447 | << ceph_entity_type_name(service_id) | |
448 | << " secret_id=" << ticket.secret_id << dendl; | |
449 | ||
450 | if (ticket.secret_id == (uint64_t)-1) { | |
451 | EntityName name; | |
452 | name.set_type(service_id); | |
9f95a23c | 453 | if (!keys.get_secret(name, service_secret)) { |
7c673cae FG |
454 | ldout(cct, 0) << "verify_authorizer could not get general service secret for service " |
455 | << ceph_entity_type_name(service_id) << " secret_id=" << ticket.secret_id << dendl; | |
456 | return false; | |
457 | } | |
458 | } else { | |
9f95a23c | 459 | if (!keys.get_service_secret(service_id, ticket.secret_id, service_secret)) { |
7c673cae FG |
460 | ldout(cct, 0) << "verify_authorizer could not get service secret for service " |
461 | << ceph_entity_type_name(service_id) << " secret_id=" << ticket.secret_id << dendl; | |
462 | if (cct->_conf->auth_debug && ticket.secret_id == 0) | |
11fdf7f2 | 463 | ceph_abort_msg("got secret_id=0"); |
7c673cae FG |
464 | return false; |
465 | } | |
466 | } | |
467 | std::string error; | |
468 | if (!service_secret.get_secret().length()) | |
469 | error = "invalid key"; // Bad key? | |
470 | else | |
471 | decode_decrypt_enc_bl(cct, ticket_info, service_secret, ticket.blob, error); | |
472 | if (!error.empty()) { | |
473 | ldout(cct, 0) << "verify_authorizer could not decrypt ticket info: error: " | |
474 | << error << dendl; | |
475 | return false; | |
476 | } | |
477 | ||
478 | if (ticket_info.ticket.global_id != global_id) { | |
479 | ldout(cct, 0) << "verify_authorizer global_id mismatch: declared id=" << global_id | |
480 | << " ticket_id=" << ticket_info.ticket.global_id << dendl; | |
481 | return false; | |
482 | } | |
483 | ||
484 | ldout(cct, 10) << "verify_authorizer global_id=" << global_id << dendl; | |
485 | ||
486 | // CephXAuthorize | |
487 | CephXAuthorize auth_msg; | |
488 | if (decode_decrypt(cct, auth_msg, ticket_info.session_key, indata, error)) { | |
489 | ldout(cct, 0) << "verify_authorizercould not decrypt authorize request with error: " | |
490 | << error << dendl; | |
491 | return false; | |
492 | } | |
493 | ||
28e407b8 AA |
494 | if (challenge) { |
495 | auto *c = static_cast<CephXAuthorizeChallenge*>(challenge->get()); | |
496 | if (!auth_msg.have_challenge || !c) { | |
497 | c = new CephXAuthorizeChallenge; | |
498 | challenge->reset(c); | |
11fdf7f2 | 499 | cct->random()->get_bytes((char*)&c->server_challenge, sizeof(c->server_challenge)); |
28e407b8 AA |
500 | ldout(cct,10) << __func__ << " adding server_challenge " << c->server_challenge |
501 | << dendl; | |
502 | ||
11fdf7f2 | 503 | encode_encrypt_enc_bl(cct, *c, ticket_info.session_key, *reply_bl, error); |
28e407b8 AA |
504 | if (!error.empty()) { |
505 | ldout(cct, 10) << "verify_authorizer: encode_encrypt error: " << error << dendl; | |
506 | return false; | |
507 | } | |
508 | return false; | |
509 | } | |
510 | ldout(cct, 10) << __func__ << " got server_challenge+1 " | |
511 | << auth_msg.server_challenge_plus_one | |
512 | << " expecting " << c->server_challenge + 1 << dendl; | |
513 | if (c->server_challenge + 1 != auth_msg.server_challenge_plus_one) { | |
514 | return false; | |
515 | } | |
516 | } | |
517 | ||
7c673cae FG |
518 | /* |
519 | * Reply authorizer: | |
520 | * {timestamp + 1}^session_key | |
521 | */ | |
522 | CephXAuthorizeReply reply; | |
523 | // reply.trans_id = auth_msg.trans_id; | |
524 | reply.nonce_plus_one = auth_msg.nonce + 1; | |
11fdf7f2 TL |
525 | if (connection_secret) { |
526 | // generate a connection secret | |
527 | connection_secret->resize(connection_secret_required_len); | |
528 | if (connection_secret_required_len) { | |
f67539c2 TL |
529 | #ifdef WITH_SEASTAR |
530 | std::random_device rd; | |
531 | std::generate_n(connection_secret->data(), | |
532 | connection_secret_required_len, | |
533 | std::default_random_engine{rd()}); | |
534 | #else | |
11fdf7f2 TL |
535 | cct->random()->get_bytes(connection_secret->data(), |
536 | connection_secret_required_len); | |
f67539c2 | 537 | #endif |
11fdf7f2 TL |
538 | } |
539 | reply.connection_secret = *connection_secret; | |
540 | } | |
11fdf7f2 | 541 | if (encode_encrypt(cct, reply, ticket_info.session_key, *reply_bl, error)) { |
7c673cae FG |
542 | ldout(cct, 10) << "verify_authorizer: encode_encrypt error: " << error << dendl; |
543 | return false; | |
544 | } | |
545 | ||
546 | ldout(cct, 10) << "verify_authorizer ok nonce " << hex << auth_msg.nonce << dec | |
11fdf7f2 | 547 | << " reply_bl.length()=" << reply_bl->length() << dendl; |
7c673cae FG |
548 | return true; |
549 | } | |
550 | ||
11fdf7f2 TL |
551 | bool CephXAuthorizer::verify_reply(bufferlist::const_iterator& indata, |
552 | std::string *connection_secret) | |
7c673cae FG |
553 | { |
554 | CephXAuthorizeReply reply; | |
555 | ||
556 | std::string error; | |
557 | if (decode_decrypt(cct, reply, session_key, indata, error)) { | |
558 | ldout(cct, 0) << "verify_reply couldn't decrypt with error: " << error << dendl; | |
559 | return false; | |
560 | } | |
561 | ||
562 | uint64_t expect = nonce + 1; | |
563 | if (expect != reply.nonce_plus_one) { | |
564 | ldout(cct, 0) << "verify_authorizer_reply bad nonce got " << reply.nonce_plus_one << " expected " << expect | |
565 | << " sent " << nonce << dendl; | |
566 | return false; | |
567 | } | |
11fdf7f2 TL |
568 | |
569 | if (connection_secret && | |
570 | reply.connection_secret.size()) { | |
571 | *connection_secret = reply.connection_secret; | |
572 | } | |
7c673cae FG |
573 | return true; |
574 | } | |
575 | ||
11fdf7f2 TL |
576 | bool CephXAuthorizer::add_challenge(CephContext *cct, |
577 | const bufferlist& challenge) | |
28e407b8 AA |
578 | { |
579 | bl = base_bl; | |
580 | ||
581 | CephXAuthorize msg; | |
582 | msg.nonce = nonce; | |
583 | ||
584 | auto p = challenge.begin(); | |
585 | if (!p.end()) { | |
586 | std::string error; | |
587 | CephXAuthorizeChallenge ch; | |
588 | decode_decrypt_enc_bl(cct, ch, session_key, challenge, error); | |
589 | if (!error.empty()) { | |
590 | ldout(cct, 0) << "failed to decrypt challenge (" << challenge.length() << " bytes): " | |
591 | << error << dendl; | |
592 | return false; | |
593 | } | |
594 | msg.have_challenge = true; | |
595 | msg.server_challenge_plus_one = ch.server_challenge + 1; | |
596 | } | |
597 | ||
598 | std::string error; | |
599 | if (encode_encrypt(cct, msg, session_key, bl, error)) { | |
600 | ldout(cct, 0) << __func__ << " failed to encrypt authorizer: " << error << dendl; | |
601 | return false; | |
602 | } | |
603 | return true; | |
604 | } |