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