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