Fix some bugs when testing opensds ansible
[stor4nfv.git] / src / 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
277   explicit CephXAuthorizer(CephContext *cct_)
278     : AuthAuthorizer(CEPH_AUTH_CEPHX), cct(cct_), nonce(0) {}
279
280   bool build_authorizer();
281   bool verify_reply(bufferlist::iterator& reply) override;
282 };
283
284
285
286 /*
287  * TicketHandler
288  */
289 struct CephXTicketHandler {
290   uint32_t service_id;
291   CryptoKey session_key;
292   CephXTicketBlob ticket;        // opaque to us
293   utime_t renew_after, expires;
294   bool have_key_flag;
295
296   CephXTicketHandler(CephContext *cct_, uint32_t service_id_)
297     : service_id(service_id_), have_key_flag(false), cct(cct_) { }
298
299   // to build our ServiceTicket
300   bool verify_service_ticket_reply(CryptoKey& principal_secret,
301                                  bufferlist::iterator& indata);
302   // to access the service
303   CephXAuthorizer *build_authorizer(uint64_t global_id) const;
304
305   bool have_key();
306   bool need_key() const;
307
308   void invalidate_ticket() {
309     have_key_flag = 0;
310   }
311 private:
312   CephContext *cct;
313 };
314
315 struct CephXTicketManager {
316   typedef map<uint32_t, CephXTicketHandler> tickets_map_t;
317   tickets_map_t tickets_map;
318   uint64_t global_id;
319
320   explicit CephXTicketManager(CephContext *cct_) : global_id(0), cct(cct_) {}
321
322   bool verify_service_ticket_reply(CryptoKey& principal_secret,
323                                  bufferlist::iterator& indata);
324
325   CephXTicketHandler& get_handler(uint32_t type) {
326     tickets_map_t::iterator i = tickets_map.find(type);
327     if (i != tickets_map.end())
328       return i->second;
329     CephXTicketHandler newTicketHandler(cct, type);
330     std::pair < tickets_map_t::iterator, bool > res =
331         tickets_map.insert(std::make_pair(type, newTicketHandler));
332     assert(res.second);
333     return res.first->second;
334   }
335   CephXAuthorizer *build_authorizer(uint32_t service_id) const;
336   bool have_key(uint32_t service_id);
337   bool need_key(uint32_t service_id) const;
338   void set_have_need_key(uint32_t service_id, uint32_t& have, uint32_t& need);
339   void validate_tickets(uint32_t mask, uint32_t& have, uint32_t& need);
340   void invalidate_ticket(uint32_t service_id);
341
342 private:
343   CephContext *cct;
344 };
345
346
347 /* A */
348 struct CephXServiceTicket {
349   CryptoKey session_key;
350   utime_t validity;
351
352   void encode(bufferlist& bl) const {
353     __u8 struct_v = 1;
354     ::encode(struct_v, bl);
355     ::encode(session_key, bl);
356     ::encode(validity, bl);
357   }
358   void decode(bufferlist::iterator& bl) {
359     __u8 struct_v;
360     ::decode(struct_v, bl);
361     ::decode(session_key, bl);
362     ::decode(validity, bl);
363   }
364 };
365 WRITE_CLASS_ENCODER(CephXServiceTicket)
366
367 /* B */
368 struct CephXServiceTicketInfo {
369   AuthTicket ticket;
370   CryptoKey session_key;
371
372   void encode(bufferlist& bl) const {
373     __u8 struct_v = 1;
374     ::encode(struct_v, bl);
375     ::encode(ticket, bl);
376     ::encode(session_key, bl);
377   }
378   void decode(bufferlist::iterator& bl) {
379     __u8 struct_v;
380     ::decode(struct_v, bl);
381     ::decode(ticket, bl);
382     ::decode(session_key, bl);
383   }
384 };
385 WRITE_CLASS_ENCODER(CephXServiceTicketInfo)
386
387 struct CephXAuthorize {
388   uint64_t nonce;
389   void encode(bufferlist& bl) const {
390     __u8 struct_v = 1;
391     ::encode(struct_v, bl);
392     ::encode(nonce, bl);
393   }
394   void decode(bufferlist::iterator& bl) {
395     __u8 struct_v;
396     ::decode(struct_v, bl);
397     ::decode(nonce, bl);
398   }
399 };
400 WRITE_CLASS_ENCODER(CephXAuthorize)
401
402 /*
403  * Decode an extract ticket
404  */
405 bool cephx_decode_ticket(CephContext *cct, KeyStore *keys,
406                          uint32_t service_id, CephXTicketBlob& ticket_blob,
407                          CephXServiceTicketInfo& ticket_info);
408
409 /*
410  * Verify authorizer and generate reply authorizer
411  */
412 extern bool cephx_verify_authorizer(CephContext *cct, KeyStore *keys,
413                                     bufferlist::iterator& indata,
414                                     CephXServiceTicketInfo& ticket_info, bufferlist& reply_bl);
415
416
417
418
419
420
421 /*
422  * encode+encrypt macros
423  */
424 static constexpr uint64_t AUTH_ENC_MAGIC = 0xff009cad8826aa55ull;
425
426 template <typename T>
427 void decode_decrypt_enc_bl(CephContext *cct, T& t, CryptoKey key, bufferlist& bl_enc, 
428                            std::string &error)
429 {
430   uint64_t magic;
431   bufferlist bl;
432
433   if (key.decrypt(cct, bl_enc, bl, &error) < 0)
434     return;
435
436   bufferlist::iterator iter2 = bl.begin();
437   __u8 struct_v;
438   ::decode(struct_v, iter2);
439   ::decode(magic, iter2);
440   if (magic != AUTH_ENC_MAGIC) {
441     ostringstream oss;
442     oss << "bad magic in decode_decrypt, " << magic << " != " << AUTH_ENC_MAGIC;
443     error = oss.str();
444     return;
445   }
446
447   ::decode(t, iter2);
448 }
449
450 template <typename T>
451 void encode_encrypt_enc_bl(CephContext *cct, const T& t, const CryptoKey& key,
452                            bufferlist& out, std::string &error)
453 {
454   bufferlist bl;
455   __u8 struct_v = 1;
456   ::encode(struct_v, bl);
457   uint64_t magic = AUTH_ENC_MAGIC;
458   ::encode(magic, bl);
459   ::encode(t, bl);
460
461   key.encrypt(cct, bl, out, &error);
462 }
463
464 template <typename T>
465 int decode_decrypt(CephContext *cct, T& t, const CryptoKey& key,
466                     bufferlist::iterator& iter, std::string &error)
467 {
468   bufferlist bl_enc;
469   try {
470     ::decode(bl_enc, iter);
471     decode_decrypt_enc_bl(cct, t, key, bl_enc, error);
472   }
473   catch (buffer::error &e) {
474     error = "error decoding block for decryption";
475   }
476   if (!error.empty())
477     return CEPHX_CRYPT_ERR;
478   return 0;
479 }
480
481 template <typename T>
482 int encode_encrypt(CephContext *cct, const T& t, const CryptoKey& key,
483                     bufferlist& out, std::string &error)
484 {
485   bufferlist bl_enc;
486   encode_encrypt_enc_bl(cct, t, key, bl_enc, error);
487   if (!error.empty()){
488     return CEPHX_CRYPT_ERR;
489   }
490   ::encode(bl_enc, out);
491   return 0;
492 }
493
494
495 #endif