]> git.proxmox.com Git - ceph.git/blame - ceph/src/auth/cephx/CephxProtocol.h
update ceph source to reef 18.1.2
[ceph.git] / ceph / src / auth / cephx / CephxProtocol.h
CommitLineData
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#ifndef CEPH_CEPHXPROTOCOL_H
16#define CEPH_CEPHXPROTOCOL_H
17
18/*
19 Ceph X protocol
20
11fdf7f2 21 See doc/dev/cephx.rst
7c673cae 22
7c673cae
FG
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
9f95a23c 37#include "include/common_fwd.h"
7c673cae
FG
38/*
39 * Authentication
40 */
41
42// initial server -> client challenge
43struct CephXServerChallenge {
44 uint64_t server_challenge;
45
f67539c2 46 void encode(ceph::buffer::list& bl) const {
11fdf7f2 47 using ceph::encode;
7c673cae 48 __u8 struct_v = 1;
11fdf7f2
TL
49 encode(struct_v, bl);
50 encode(server_challenge, bl);
7c673cae 51 }
f67539c2 52 void decode(ceph::buffer::list::const_iterator& bl) {
11fdf7f2 53 using ceph::decode;
7c673cae 54 __u8 struct_v;
11fdf7f2
TL
55 decode(struct_v, bl);
56 decode(server_challenge, bl);
7c673cae
FG
57 }
58};
59WRITE_CLASS_ENCODER(CephXServerChallenge)
60
61
62// request/reply headers, for subsequent exchanges.
63
64struct CephXRequestHeader {
65 __u16 request_type;
66
f67539c2 67 void encode(ceph::buffer::list& bl) const {
11fdf7f2
TL
68 using ceph::encode;
69 encode(request_type, bl);
7c673cae 70 }
f67539c2 71 void decode(ceph::buffer::list::const_iterator& bl) {
11fdf7f2
TL
72 using ceph::decode;
73 decode(request_type, bl);
7c673cae
FG
74 }
75};
76WRITE_CLASS_ENCODER(CephXRequestHeader)
77
78struct CephXResponseHeader {
79 uint16_t request_type;
80 int32_t status;
81
f67539c2 82 void encode(ceph::buffer::list& bl) const {
11fdf7f2
TL
83 using ceph::encode;
84 encode(request_type, bl);
85 encode(status, bl);
7c673cae 86 }
f67539c2 87 void decode(ceph::buffer::list::const_iterator& bl) {
11fdf7f2
TL
88 using ceph::decode;
89 decode(request_type, bl);
90 decode(status, bl);
7c673cae
FG
91 }
92};
93WRITE_CLASS_ENCODER(CephXResponseHeader)
94
95struct CephXTicketBlob {
96 uint64_t secret_id;
f67539c2 97 ceph::buffer::list blob;
7c673cae
FG
98
99 CephXTicketBlob() : secret_id(0) {}
100
f67539c2 101 void encode(ceph::buffer::list& bl) const {
11fdf7f2 102 using ceph::encode;
7c673cae 103 __u8 struct_v = 1;
11fdf7f2
TL
104 encode(struct_v, bl);
105 encode(secret_id, bl);
106 encode(blob, bl);
7c673cae
FG
107 }
108
f67539c2 109 void decode(ceph::buffer::list::const_iterator& bl) {
11fdf7f2
TL
110 using ceph::decode;
111 __u8 struct_v;
112 decode(struct_v, bl);
113 decode(secret_id, bl);
114 decode(blob, bl);
7c673cae
FG
115 }
116};
117WRITE_CLASS_ENCODER(CephXTicketBlob)
118
119// client -> server response to challenge
120struct CephXAuthenticate {
121 uint64_t client_challenge;
122 uint64_t key;
123 CephXTicketBlob old_ticket;
11fdf7f2 124 uint32_t other_keys = 0; // replaces CephXServiceTicketRequest
7c673cae 125
c5c27e9a
TL
126 bool old_ticket_may_be_omitted;
127
f67539c2 128 void encode(ceph::buffer::list& bl) const {
11fdf7f2 129 using ceph::encode;
c5c27e9a 130 __u8 struct_v = 3;
11fdf7f2
TL
131 encode(struct_v, bl);
132 encode(client_challenge, bl);
133 encode(key, bl);
134 encode(old_ticket, bl);
135 encode(other_keys, bl);
7c673cae 136 }
f67539c2 137 void decode(ceph::buffer::list::const_iterator& bl) {
11fdf7f2 138 using ceph::decode;
7c673cae 139 __u8 struct_v;
11fdf7f2
TL
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 }
c5c27e9a
TL
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;
11fdf7f2 154 }
7c673cae
FG
155};
156WRITE_CLASS_ENCODER(CephXAuthenticate)
157
158struct CephXChallengeBlob {
159 uint64_t server_challenge, client_challenge;
160
f67539c2 161 void encode(ceph::buffer::list& bl) const {
11fdf7f2
TL
162 using ceph::encode;
163 encode(server_challenge, bl);
164 encode(client_challenge, bl);
7c673cae 165 }
f67539c2 166 void decode(ceph::buffer::list::const_iterator& bl) {
11fdf7f2
TL
167 using ceph::decode;
168 decode(server_challenge, bl);
169 decode(client_challenge, bl);
7c673cae
FG
170 }
171};
172WRITE_CLASS_ENCODER(CephXChallengeBlob)
173
174void 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 */
182struct 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
192extern bool cephx_build_service_ticket_blob(CephContext *cct,
193 CephXSessionAuthInfo& ticket_info, CephXTicketBlob& blob);
194
195extern void cephx_build_service_ticket_request(CephContext *cct,
196 uint32_t keys,
f67539c2 197 ceph::buffer::list& request);
7c673cae
FG
198
199extern bool cephx_build_service_ticket_reply(CephContext *cct,
200 CryptoKey& principal_secret,
f67539c2 201 std::vector<CephXSessionAuthInfo> ticket_info,
7c673cae
FG
202 bool should_encrypt_ticket,
203 CryptoKey& ticket_enc_key,
f67539c2 204 ceph::buffer::list& reply);
7c673cae
FG
205
206struct CephXServiceTicketRequest {
207 uint32_t keys;
208
f67539c2 209 void encode(ceph::buffer::list& bl) const {
11fdf7f2 210 using ceph::encode;
7c673cae 211 __u8 struct_v = 1;
11fdf7f2
TL
212 encode(struct_v, bl);
213 encode(keys, bl);
7c673cae 214 }
f67539c2 215 void decode(ceph::buffer::list::const_iterator& bl) {
11fdf7f2 216 using ceph::decode;
7c673cae 217 __u8 struct_v;
11fdf7f2
TL
218 decode(struct_v, bl);
219 decode(keys, bl);
7c673cae
FG
220 }
221};
222WRITE_CLASS_ENCODER(CephXServiceTicketRequest)
223
224
225/*
226 * Authorize
227 */
228
229struct CephXAuthorizeReply {
230 uint64_t nonce_plus_one;
11fdf7f2 231 std::string connection_secret;
f67539c2 232 void encode(ceph::buffer::list& bl) const {
11fdf7f2 233 using ceph::encode;
7c673cae 234 __u8 struct_v = 1;
11fdf7f2
TL
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 }
7c673cae 244 }
f67539c2 245 void decode(ceph::buffer::list::const_iterator& bl) {
11fdf7f2 246 using ceph::decode;
7c673cae 247 __u8 struct_v;
11fdf7f2
TL
248 decode(struct_v, bl);
249 decode(nonce_plus_one, bl);
250 if (struct_v >= 2) {
251 decode(connection_secret, bl);
252 }
7c673cae
FG
253 }
254};
255WRITE_CLASS_ENCODER(CephXAuthorizeReply)
256
257
258struct CephXAuthorizer : public AuthAuthorizer {
259private:
260 CephContext *cct;
261public:
262 uint64_t nonce;
f67539c2 263 ceph::buffer::list base_bl;
7c673cae
FG
264
265 explicit CephXAuthorizer(CephContext *cct_)
266 : AuthAuthorizer(CEPH_AUTH_CEPHX), cct(cct_), nonce(0) {}
267
268 bool build_authorizer();
f67539c2 269 bool verify_reply(ceph::buffer::list::const_iterator& reply,
11fdf7f2 270 std::string *connection_secret) override;
f67539c2 271 bool add_challenge(CephContext *cct, const ceph::buffer::list& challenge) override;
7c673cae
FG
272};
273
274
275
276/*
277 * TicketHandler
278 */
279struct 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,
f67539c2 291 ceph::buffer::list::const_iterator& indata);
7c673cae
FG
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() {
1e59de90 299 have_key_flag = false;
7c673cae
FG
300 }
301private:
302 CephContext *cct;
303};
304
305struct CephXTicketManager {
f67539c2 306 typedef std::map<uint32_t, CephXTicketHandler> tickets_map_t;
7c673cae
FG
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,
f67539c2 313 ceph::buffer::list::const_iterator& indata);
7c673cae
FG
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));
11fdf7f2 322 ceph_assert(res.second);
7c673cae
FG
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
332private:
333 CephContext *cct;
334};
335
336
337/* A */
338struct CephXServiceTicket {
339 CryptoKey session_key;
340 utime_t validity;
341
f67539c2 342 void encode(ceph::buffer::list& bl) const {
11fdf7f2 343 using ceph::encode;
7c673cae 344 __u8 struct_v = 1;
11fdf7f2
TL
345 encode(struct_v, bl);
346 encode(session_key, bl);
347 encode(validity, bl);
7c673cae 348 }
f67539c2 349 void decode(ceph::buffer::list::const_iterator& bl) {
11fdf7f2 350 using ceph::decode;
7c673cae 351 __u8 struct_v;
11fdf7f2
TL
352 decode(struct_v, bl);
353 decode(session_key, bl);
354 decode(validity, bl);
7c673cae
FG
355 }
356};
357WRITE_CLASS_ENCODER(CephXServiceTicket)
358
359/* B */
360struct CephXServiceTicketInfo {
361 AuthTicket ticket;
362 CryptoKey session_key;
363
f67539c2 364 void encode(ceph::buffer::list& bl) const {
11fdf7f2 365 using ceph::encode;
7c673cae 366 __u8 struct_v = 1;
11fdf7f2
TL
367 encode(struct_v, bl);
368 encode(ticket, bl);
369 encode(session_key, bl);
7c673cae 370 }
f67539c2 371 void decode(ceph::buffer::list::const_iterator& bl) {
11fdf7f2 372 using ceph::decode;
7c673cae 373 __u8 struct_v;
11fdf7f2
TL
374 decode(struct_v, bl);
375 decode(ticket, bl);
376 decode(session_key, bl);
7c673cae
FG
377 }
378};
379WRITE_CLASS_ENCODER(CephXServiceTicketInfo)
380
28e407b8
AA
381struct CephXAuthorizeChallenge : public AuthAuthorizerChallenge {
382 uint64_t server_challenge;
f67539c2 383 void encode(ceph::buffer::list& bl) const {
11fdf7f2 384 using ceph::encode;
28e407b8 385 __u8 struct_v = 1;
11fdf7f2
TL
386 encode(struct_v, bl);
387 encode(server_challenge, bl);
28e407b8 388 }
f67539c2 389 void decode(ceph::buffer::list::const_iterator& bl) {
11fdf7f2 390 using ceph::decode;
28e407b8 391 __u8 struct_v;
11fdf7f2
TL
392 decode(struct_v, bl);
393 decode(server_challenge, bl);
28e407b8
AA
394 }
395};
396WRITE_CLASS_ENCODER(CephXAuthorizeChallenge)
397
7c673cae
FG
398struct CephXAuthorize {
399 uint64_t nonce;
28e407b8
AA
400 bool have_challenge = false;
401 uint64_t server_challenge_plus_one = 0;
f67539c2 402 void encode(ceph::buffer::list& bl) const {
11fdf7f2 403 using ceph::encode;
28e407b8 404 __u8 struct_v = 2;
11fdf7f2
TL
405 encode(struct_v, bl);
406 encode(nonce, bl);
407 encode(have_challenge, bl);
408 encode(server_challenge_plus_one, bl);
7c673cae 409 }
f67539c2 410 void decode(ceph::buffer::list::const_iterator& bl) {
11fdf7f2 411 using ceph::decode;
7c673cae 412 __u8 struct_v;
11fdf7f2
TL
413 decode(struct_v, bl);
414 decode(nonce, bl);
28e407b8 415 if (struct_v >= 2) {
11fdf7f2
TL
416 decode(have_challenge, bl);
417 decode(server_challenge_plus_one, bl);
28e407b8 418 }
7c673cae
FG
419 }
420};
421WRITE_CLASS_ENCODER(CephXAuthorize)
422
423/*
424 * Decode an extract ticket
425 */
426bool cephx_decode_ticket(CephContext *cct, KeyStore *keys,
c5c27e9a
TL
427 uint32_t service_id,
428 const CephXTicketBlob& ticket_blob,
7c673cae
FG
429 CephXServiceTicketInfo& ticket_info);
430
431/*
432 * Verify authorizer and generate reply authorizer
433 */
28e407b8 434extern bool cephx_verify_authorizer(
11fdf7f2 435 CephContext *cct,
9f95a23c 436 const KeyStore& keys,
f67539c2 437 ceph::buffer::list::const_iterator& indata,
11fdf7f2 438 size_t connection_secret_required_len,
28e407b8
AA
439 CephXServiceTicketInfo& ticket_info,
440 std::unique_ptr<AuthAuthorizerChallenge> *challenge,
11fdf7f2 441 std::string *connection_secret,
f67539c2 442 ceph::buffer::list *reply_bl);
7c673cae
FG
443
444
445
446
447
448
449/*
450 * encode+encrypt macros
451 */
452static constexpr uint64_t AUTH_ENC_MAGIC = 0xff009cad8826aa55ull;
453
454template <typename T>
11fdf7f2 455void decode_decrypt_enc_bl(CephContext *cct, T& t, CryptoKey key,
f67539c2 456 const ceph::buffer::list& bl_enc,
7c673cae
FG
457 std::string &error)
458{
459 uint64_t magic;
f67539c2 460 ceph::buffer::list bl;
7c673cae
FG
461
462 if (key.decrypt(cct, bl_enc, bl, &error) < 0)
463 return;
464
11fdf7f2 465 auto iter2 = bl.cbegin();
7c673cae 466 __u8 struct_v;
f67539c2 467 using ceph::decode;
11fdf7f2
TL
468 decode(struct_v, iter2);
469 decode(magic, iter2);
7c673cae 470 if (magic != AUTH_ENC_MAGIC) {
f67539c2 471 std::ostringstream oss;
7c673cae
FG
472 oss << "bad magic in decode_decrypt, " << magic << " != " << AUTH_ENC_MAGIC;
473 error = oss.str();
474 return;
475 }
476
11fdf7f2 477 decode(t, iter2);
7c673cae
FG
478}
479
480template <typename T>
481void encode_encrypt_enc_bl(CephContext *cct, const T& t, const CryptoKey& key,
f67539c2 482 ceph::buffer::list& out, std::string &error)
7c673cae 483{
f67539c2 484 ceph::buffer::list bl;
7c673cae 485 __u8 struct_v = 1;
f67539c2 486 using ceph::encode;
11fdf7f2 487 encode(struct_v, bl);
7c673cae 488 uint64_t magic = AUTH_ENC_MAGIC;
11fdf7f2
TL
489 encode(magic, bl);
490 encode(t, bl);
7c673cae
FG
491
492 key.encrypt(cct, bl, out, &error);
493}
494
495template <typename T>
496int decode_decrypt(CephContext *cct, T& t, const CryptoKey& key,
f67539c2 497 ceph::buffer::list::const_iterator& iter, std::string &error)
7c673cae 498{
f67539c2
TL
499 ceph::buffer::list bl_enc;
500 using ceph::decode;
7c673cae 501 try {
11fdf7f2 502 decode(bl_enc, iter);
7c673cae
FG
503 decode_decrypt_enc_bl(cct, t, key, bl_enc, error);
504 }
f67539c2 505 catch (ceph::buffer::error &e) {
7c673cae
FG
506 error = "error decoding block for decryption";
507 }
508 if (!error.empty())
509 return CEPHX_CRYPT_ERR;
510 return 0;
511}
512
513template <typename T>
514int encode_encrypt(CephContext *cct, const T& t, const CryptoKey& key,
f67539c2 515 ceph::buffer::list& out, std::string &error)
7c673cae 516{
f67539c2
TL
517 using ceph::encode;
518 ceph::buffer::list bl_enc;
7c673cae
FG
519 encode_encrypt_enc_bl(cct, t, key, bl_enc, error);
520 if (!error.empty()){
521 return CEPHX_CRYPT_ERR;
522 }
11fdf7f2 523 encode(bl_enc, out);
7c673cae
FG
524 return 0;
525}
526
7c673cae 527#endif