]> git.proxmox.com Git - ceph.git/blob - ceph/src/auth/cephx/CephxProtocol.h
update ceph source to reef 18.1.2
[ceph.git] / ceph / src / auth / cephx / CephxProtocol.h
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 #ifndef CEPH_CEPHXPROTOCOL_H
16 #define CEPH_CEPHXPROTOCOL_H
17
18 /*
19 Ceph X protocol
20
21 See doc/dev/cephx.rst
22
23 */
24
25 /* authenticate requests */
26 #define CEPHX_GET_AUTH_SESSION_KEY 0x0100
27 #define CEPHX_GET_PRINCIPAL_SESSION_KEY 0x0200
28 #define CEPHX_GET_ROTATING_KEY 0x0400
29
30 #define CEPHX_REQUEST_TYPE_MASK 0x0F00
31 #define CEPHX_CRYPT_ERR 1
32
33 #include "auth/Auth.h"
34 #include <errno.h>
35 #include <sstream>
36
37 #include "include/common_fwd.h"
38 /*
39 * Authentication
40 */
41
42 // initial server -> client challenge
43 struct CephXServerChallenge {
44 uint64_t server_challenge;
45
46 void encode(ceph::buffer::list& bl) const {
47 using ceph::encode;
48 __u8 struct_v = 1;
49 encode(struct_v, bl);
50 encode(server_challenge, bl);
51 }
52 void decode(ceph::buffer::list::const_iterator& bl) {
53 using ceph::decode;
54 __u8 struct_v;
55 decode(struct_v, bl);
56 decode(server_challenge, bl);
57 }
58 };
59 WRITE_CLASS_ENCODER(CephXServerChallenge)
60
61
62 // request/reply headers, for subsequent exchanges.
63
64 struct CephXRequestHeader {
65 __u16 request_type;
66
67 void encode(ceph::buffer::list& bl) const {
68 using ceph::encode;
69 encode(request_type, bl);
70 }
71 void decode(ceph::buffer::list::const_iterator& bl) {
72 using ceph::decode;
73 decode(request_type, bl);
74 }
75 };
76 WRITE_CLASS_ENCODER(CephXRequestHeader)
77
78 struct CephXResponseHeader {
79 uint16_t request_type;
80 int32_t status;
81
82 void encode(ceph::buffer::list& bl) const {
83 using ceph::encode;
84 encode(request_type, bl);
85 encode(status, bl);
86 }
87 void decode(ceph::buffer::list::const_iterator& bl) {
88 using ceph::decode;
89 decode(request_type, bl);
90 decode(status, bl);
91 }
92 };
93 WRITE_CLASS_ENCODER(CephXResponseHeader)
94
95 struct CephXTicketBlob {
96 uint64_t secret_id;
97 ceph::buffer::list blob;
98
99 CephXTicketBlob() : secret_id(0) {}
100
101 void encode(ceph::buffer::list& bl) const {
102 using ceph::encode;
103 __u8 struct_v = 1;
104 encode(struct_v, bl);
105 encode(secret_id, bl);
106 encode(blob, bl);
107 }
108
109 void decode(ceph::buffer::list::const_iterator& bl) {
110 using ceph::decode;
111 __u8 struct_v;
112 decode(struct_v, bl);
113 decode(secret_id, bl);
114 decode(blob, bl);
115 }
116 };
117 WRITE_CLASS_ENCODER(CephXTicketBlob)
118
119 // client -> server response to challenge
120 struct CephXAuthenticate {
121 uint64_t client_challenge;
122 uint64_t key;
123 CephXTicketBlob old_ticket;
124 uint32_t other_keys = 0; // replaces CephXServiceTicketRequest
125
126 bool old_ticket_may_be_omitted;
127
128 void encode(ceph::buffer::list& bl) const {
129 using ceph::encode;
130 __u8 struct_v = 3;
131 encode(struct_v, bl);
132 encode(client_challenge, bl);
133 encode(key, bl);
134 encode(old_ticket, bl);
135 encode(other_keys, bl);
136 }
137 void decode(ceph::buffer::list::const_iterator& bl) {
138 using ceph::decode;
139 __u8 struct_v;
140 decode(struct_v, bl);
141 decode(client_challenge, bl);
142 decode(key, bl);
143 decode(old_ticket, bl);
144 if (struct_v >= 2) {
145 decode(other_keys, bl);
146 }
147
148 // v2 and v3 encodings are the same, but:
149 // - some clients that send v1 or v2 don't populate old_ticket
150 // on reconnects (but do on renewals)
151 // - any client that sends v3 or later is expected to populate
152 // old_ticket both on reconnects and renewals
153 old_ticket_may_be_omitted = struct_v < 3;
154 }
155 };
156 WRITE_CLASS_ENCODER(CephXAuthenticate)
157
158 struct CephXChallengeBlob {
159 uint64_t server_challenge, client_challenge;
160
161 void encode(ceph::buffer::list& bl) const {
162 using ceph::encode;
163 encode(server_challenge, bl);
164 encode(client_challenge, bl);
165 }
166 void decode(ceph::buffer::list::const_iterator& bl) {
167 using ceph::decode;
168 decode(server_challenge, bl);
169 decode(client_challenge, bl);
170 }
171 };
172 WRITE_CLASS_ENCODER(CephXChallengeBlob)
173
174 void cephx_calc_client_server_challenge(CephContext *cct,
175 CryptoKey& secret, uint64_t server_challenge, uint64_t client_challenge,
176 uint64_t *key, std::string &error);
177
178
179 /*
180 * getting service tickets
181 */
182 struct CephXSessionAuthInfo {
183 uint32_t service_id;
184 uint64_t secret_id;
185 AuthTicket ticket;
186 CryptoKey session_key;
187 CryptoKey service_secret;
188 utime_t validity;
189 };
190
191
192 extern bool cephx_build_service_ticket_blob(CephContext *cct,
193 CephXSessionAuthInfo& ticket_info, CephXTicketBlob& blob);
194
195 extern void cephx_build_service_ticket_request(CephContext *cct,
196 uint32_t keys,
197 ceph::buffer::list& request);
198
199 extern bool cephx_build_service_ticket_reply(CephContext *cct,
200 CryptoKey& principal_secret,
201 std::vector<CephXSessionAuthInfo> ticket_info,
202 bool should_encrypt_ticket,
203 CryptoKey& ticket_enc_key,
204 ceph::buffer::list& reply);
205
206 struct CephXServiceTicketRequest {
207 uint32_t keys;
208
209 void encode(ceph::buffer::list& bl) const {
210 using ceph::encode;
211 __u8 struct_v = 1;
212 encode(struct_v, bl);
213 encode(keys, bl);
214 }
215 void decode(ceph::buffer::list::const_iterator& bl) {
216 using ceph::decode;
217 __u8 struct_v;
218 decode(struct_v, bl);
219 decode(keys, bl);
220 }
221 };
222 WRITE_CLASS_ENCODER(CephXServiceTicketRequest)
223
224
225 /*
226 * Authorize
227 */
228
229 struct CephXAuthorizeReply {
230 uint64_t nonce_plus_one;
231 std::string connection_secret;
232 void encode(ceph::buffer::list& bl) const {
233 using ceph::encode;
234 __u8 struct_v = 1;
235 if (connection_secret.size()) {
236 struct_v = 2;
237 }
238 encode(struct_v, bl);
239 encode(nonce_plus_one, bl);
240 if (struct_v >= 2) {
241 struct_v = 2;
242 encode(connection_secret, bl);
243 }
244 }
245 void decode(ceph::buffer::list::const_iterator& bl) {
246 using ceph::decode;
247 __u8 struct_v;
248 decode(struct_v, bl);
249 decode(nonce_plus_one, bl);
250 if (struct_v >= 2) {
251 decode(connection_secret, bl);
252 }
253 }
254 };
255 WRITE_CLASS_ENCODER(CephXAuthorizeReply)
256
257
258 struct CephXAuthorizer : public AuthAuthorizer {
259 private:
260 CephContext *cct;
261 public:
262 uint64_t nonce;
263 ceph::buffer::list base_bl;
264
265 explicit CephXAuthorizer(CephContext *cct_)
266 : AuthAuthorizer(CEPH_AUTH_CEPHX), cct(cct_), nonce(0) {}
267
268 bool build_authorizer();
269 bool verify_reply(ceph::buffer::list::const_iterator& reply,
270 std::string *connection_secret) override;
271 bool add_challenge(CephContext *cct, const ceph::buffer::list& challenge) override;
272 };
273
274
275
276 /*
277 * TicketHandler
278 */
279 struct CephXTicketHandler {
280 uint32_t service_id;
281 CryptoKey session_key;
282 CephXTicketBlob ticket; // opaque to us
283 utime_t renew_after, expires;
284 bool have_key_flag;
285
286 CephXTicketHandler(CephContext *cct_, uint32_t service_id_)
287 : service_id(service_id_), have_key_flag(false), cct(cct_) { }
288
289 // to build our ServiceTicket
290 bool verify_service_ticket_reply(CryptoKey& principal_secret,
291 ceph::buffer::list::const_iterator& indata);
292 // to access the service
293 CephXAuthorizer *build_authorizer(uint64_t global_id) const;
294
295 bool have_key();
296 bool need_key() const;
297
298 void invalidate_ticket() {
299 have_key_flag = false;
300 }
301 private:
302 CephContext *cct;
303 };
304
305 struct CephXTicketManager {
306 typedef std::map<uint32_t, CephXTicketHandler> tickets_map_t;
307 tickets_map_t tickets_map;
308 uint64_t global_id;
309
310 explicit CephXTicketManager(CephContext *cct_) : global_id(0), cct(cct_) {}
311
312 bool verify_service_ticket_reply(CryptoKey& principal_secret,
313 ceph::buffer::list::const_iterator& indata);
314
315 CephXTicketHandler& get_handler(uint32_t type) {
316 tickets_map_t::iterator i = tickets_map.find(type);
317 if (i != tickets_map.end())
318 return i->second;
319 CephXTicketHandler newTicketHandler(cct, type);
320 std::pair < tickets_map_t::iterator, bool > res =
321 tickets_map.insert(std::make_pair(type, newTicketHandler));
322 ceph_assert(res.second);
323 return res.first->second;
324 }
325 CephXAuthorizer *build_authorizer(uint32_t service_id) const;
326 bool have_key(uint32_t service_id);
327 bool need_key(uint32_t service_id) const;
328 void set_have_need_key(uint32_t service_id, uint32_t& have, uint32_t& need);
329 void validate_tickets(uint32_t mask, uint32_t& have, uint32_t& need);
330 void invalidate_ticket(uint32_t service_id);
331
332 private:
333 CephContext *cct;
334 };
335
336
337 /* A */
338 struct CephXServiceTicket {
339 CryptoKey session_key;
340 utime_t validity;
341
342 void encode(ceph::buffer::list& bl) const {
343 using ceph::encode;
344 __u8 struct_v = 1;
345 encode(struct_v, bl);
346 encode(session_key, bl);
347 encode(validity, bl);
348 }
349 void decode(ceph::buffer::list::const_iterator& bl) {
350 using ceph::decode;
351 __u8 struct_v;
352 decode(struct_v, bl);
353 decode(session_key, bl);
354 decode(validity, bl);
355 }
356 };
357 WRITE_CLASS_ENCODER(CephXServiceTicket)
358
359 /* B */
360 struct CephXServiceTicketInfo {
361 AuthTicket ticket;
362 CryptoKey session_key;
363
364 void encode(ceph::buffer::list& bl) const {
365 using ceph::encode;
366 __u8 struct_v = 1;
367 encode(struct_v, bl);
368 encode(ticket, bl);
369 encode(session_key, bl);
370 }
371 void decode(ceph::buffer::list::const_iterator& bl) {
372 using ceph::decode;
373 __u8 struct_v;
374 decode(struct_v, bl);
375 decode(ticket, bl);
376 decode(session_key, bl);
377 }
378 };
379 WRITE_CLASS_ENCODER(CephXServiceTicketInfo)
380
381 struct CephXAuthorizeChallenge : public AuthAuthorizerChallenge {
382 uint64_t server_challenge;
383 void encode(ceph::buffer::list& bl) const {
384 using ceph::encode;
385 __u8 struct_v = 1;
386 encode(struct_v, bl);
387 encode(server_challenge, bl);
388 }
389 void decode(ceph::buffer::list::const_iterator& bl) {
390 using ceph::decode;
391 __u8 struct_v;
392 decode(struct_v, bl);
393 decode(server_challenge, bl);
394 }
395 };
396 WRITE_CLASS_ENCODER(CephXAuthorizeChallenge)
397
398 struct CephXAuthorize {
399 uint64_t nonce;
400 bool have_challenge = false;
401 uint64_t server_challenge_plus_one = 0;
402 void encode(ceph::buffer::list& bl) const {
403 using ceph::encode;
404 __u8 struct_v = 2;
405 encode(struct_v, bl);
406 encode(nonce, bl);
407 encode(have_challenge, bl);
408 encode(server_challenge_plus_one, bl);
409 }
410 void decode(ceph::buffer::list::const_iterator& bl) {
411 using ceph::decode;
412 __u8 struct_v;
413 decode(struct_v, bl);
414 decode(nonce, bl);
415 if (struct_v >= 2) {
416 decode(have_challenge, bl);
417 decode(server_challenge_plus_one, bl);
418 }
419 }
420 };
421 WRITE_CLASS_ENCODER(CephXAuthorize)
422
423 /*
424 * Decode an extract ticket
425 */
426 bool cephx_decode_ticket(CephContext *cct, KeyStore *keys,
427 uint32_t service_id,
428 const CephXTicketBlob& ticket_blob,
429 CephXServiceTicketInfo& ticket_info);
430
431 /*
432 * Verify authorizer and generate reply authorizer
433 */
434 extern bool cephx_verify_authorizer(
435 CephContext *cct,
436 const KeyStore& keys,
437 ceph::buffer::list::const_iterator& indata,
438 size_t connection_secret_required_len,
439 CephXServiceTicketInfo& ticket_info,
440 std::unique_ptr<AuthAuthorizerChallenge> *challenge,
441 std::string *connection_secret,
442 ceph::buffer::list *reply_bl);
443
444
445
446
447
448
449 /*
450 * encode+encrypt macros
451 */
452 static constexpr uint64_t AUTH_ENC_MAGIC = 0xff009cad8826aa55ull;
453
454 template <typename T>
455 void decode_decrypt_enc_bl(CephContext *cct, T& t, CryptoKey key,
456 const ceph::buffer::list& bl_enc,
457 std::string &error)
458 {
459 uint64_t magic;
460 ceph::buffer::list bl;
461
462 if (key.decrypt(cct, bl_enc, bl, &error) < 0)
463 return;
464
465 auto iter2 = bl.cbegin();
466 __u8 struct_v;
467 using ceph::decode;
468 decode(struct_v, iter2);
469 decode(magic, iter2);
470 if (magic != AUTH_ENC_MAGIC) {
471 std::ostringstream oss;
472 oss << "bad magic in decode_decrypt, " << magic << " != " << AUTH_ENC_MAGIC;
473 error = oss.str();
474 return;
475 }
476
477 decode(t, iter2);
478 }
479
480 template <typename T>
481 void encode_encrypt_enc_bl(CephContext *cct, const T& t, const CryptoKey& key,
482 ceph::buffer::list& out, std::string &error)
483 {
484 ceph::buffer::list bl;
485 __u8 struct_v = 1;
486 using ceph::encode;
487 encode(struct_v, bl);
488 uint64_t magic = AUTH_ENC_MAGIC;
489 encode(magic, bl);
490 encode(t, bl);
491
492 key.encrypt(cct, bl, out, &error);
493 }
494
495 template <typename T>
496 int decode_decrypt(CephContext *cct, T& t, const CryptoKey& key,
497 ceph::buffer::list::const_iterator& iter, std::string &error)
498 {
499 ceph::buffer::list bl_enc;
500 using ceph::decode;
501 try {
502 decode(bl_enc, iter);
503 decode_decrypt_enc_bl(cct, t, key, bl_enc, error);
504 }
505 catch (ceph::buffer::error &e) {
506 error = "error decoding block for decryption";
507 }
508 if (!error.empty())
509 return CEPHX_CRYPT_ERR;
510 return 0;
511 }
512
513 template <typename T>
514 int encode_encrypt(CephContext *cct, const T& t, const CryptoKey& key,
515 ceph::buffer::list& out, std::string &error)
516 {
517 using ceph::encode;
518 ceph::buffer::list bl_enc;
519 encode_encrypt_enc_bl(cct, t, key, bl_enc, error);
520 if (!error.empty()){
521 return CEPHX_CRYPT_ERR;
522 }
523 encode(bl_enc, out);
524 return 0;
525 }
526
527 #endif