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