1 // -*- mode:C++; tab-width:8; c-basic-offset:2; indent-tabs-mode:t -*-
2 // vim: ts=8 sw=2 smarttab
4 * Ceph - scalable distributed file system
6 * Copyright (C) 2004-2009 Sage Weil <sage@newdream.net>
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.
15 #ifndef CEPH_CEPHXPROTOCOL_H
16 #define CEPH_CEPHXPROTOCOL_H
21 First, the principal has to authenticate with the authenticator. A
22 shared-secret mechanism is being used, and the negotitaion goes like this:
28 1. Obtaining principal/auth session key
30 (Authenticate Request)
31 p->a : principal, principal_addr. authenticate me!
33 ...authenticator does lookup in database...
35 a->p : A= {principal/auth session key, validity}^principal_secret (*)
36 B= {principal ticket, validity, principal/auth session key}^authsecret
39 [principal/auth session key, validity] = service ticket
40 [principal ticket, validity, principal/auth session key] = service ticket info
42 (*) annotation: ^ signifies 'encrypted by'
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:
48 2. Obtaining principal/service session key
50 p->a : B, {principal_addr, timestamp}^principal/auth session key. authorize
52 a->p : E= {service ticket}^svcsecret
53 F= {principal/service session key, validity}^principal/auth session key
55 principal_addr, timestamp = authenticator
57 service ticket = principal name, client network address, validity, principal/service session key
59 Note that steps 1 and 2 are pretty much the same thing; contacting the
60 authenticator and requesting for a key.
62 Following this the principal should have a principal/service session key that
63 could be used later on for creating a session:
65 3. Opening a session to a service
67 p->s : E + {principal_addr, timestamp}^principal/service session key
68 s->p : {timestamp+1}^principal/service/session key
70 timestamp+1 = reply authenticator
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.
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
83 #define CEPHX_REQUEST_TYPE_MASK 0x0F00
84 #define CEPHX_CRYPT_ERR 1
86 #include "auth/Auth.h"
96 // initial server -> client challenge
97 struct CephXServerChallenge {
98 uint64_t server_challenge;
100 void encode(bufferlist& bl) const {
102 ::encode(struct_v, bl);
103 ::encode(server_challenge, bl);
105 void decode(bufferlist::iterator& bl) {
107 ::decode(struct_v, bl);
108 ::decode(server_challenge, bl);
111 WRITE_CLASS_ENCODER(CephXServerChallenge)
114 // request/reply headers, for subsequent exchanges.
116 struct CephXRequestHeader {
119 void encode(bufferlist& bl) const {
120 ::encode(request_type, bl);
122 void decode(bufferlist::iterator& bl) {
123 ::decode(request_type, bl);
126 WRITE_CLASS_ENCODER(CephXRequestHeader)
128 struct CephXResponseHeader {
129 uint16_t request_type;
132 void encode(bufferlist& bl) const {
133 ::encode(request_type, bl);
134 ::encode(status, bl);
136 void decode(bufferlist::iterator& bl) {
137 ::decode(request_type, bl);
138 ::decode(status, bl);
141 WRITE_CLASS_ENCODER(CephXResponseHeader)
143 struct CephXTicketBlob {
147 CephXTicketBlob() : secret_id(0) {}
149 void encode(bufferlist& bl) const {
151 ::encode(struct_v, bl);
152 ::encode(secret_id, bl);
156 void decode(bufferlist::iterator& bl) {
158 ::decode(struct_v, bl);
159 ::decode(secret_id, bl);
163 WRITE_CLASS_ENCODER(CephXTicketBlob)
165 // client -> server response to challenge
166 struct CephXAuthenticate {
167 uint64_t client_challenge;
169 CephXTicketBlob old_ticket;
171 void encode(bufferlist& bl) const {
173 ::encode(struct_v, bl);
174 ::encode(client_challenge, bl);
176 ::encode(old_ticket, bl);
178 void decode(bufferlist::iterator& bl) {
180 ::decode(struct_v, bl);
181 ::decode(client_challenge, bl);
183 ::decode(old_ticket, bl);
186 WRITE_CLASS_ENCODER(CephXAuthenticate)
188 struct CephXChallengeBlob {
189 uint64_t server_challenge, client_challenge;
191 void encode(bufferlist& bl) const {
192 ::encode(server_challenge, bl);
193 ::encode(client_challenge, bl);
195 void decode(bufferlist::iterator& bl) {
196 ::decode(server_challenge, bl);
197 ::decode(client_challenge, bl);
200 WRITE_CLASS_ENCODER(CephXChallengeBlob)
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);
208 * getting service tickets
210 struct CephXSessionAuthInfo {
214 CryptoKey session_key;
215 CryptoKey service_secret;
220 extern bool cephx_build_service_ticket_blob(CephContext *cct,
221 CephXSessionAuthInfo& ticket_info, CephXTicketBlob& blob);
223 extern void cephx_build_service_ticket_request(CephContext *cct,
225 bufferlist& request);
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,
234 struct CephXServiceTicketRequest {
237 void encode(bufferlist& bl) const {
239 ::encode(struct_v, bl);
242 void decode(bufferlist::iterator& bl) {
244 ::decode(struct_v, bl);
248 WRITE_CLASS_ENCODER(CephXServiceTicketRequest)
255 struct CephXAuthorizeReply {
256 uint64_t nonce_plus_one;
257 void encode(bufferlist& bl) const {
259 ::encode(struct_v, bl);
260 ::encode(nonce_plus_one, bl);
262 void decode(bufferlist::iterator& bl) {
264 ::decode(struct_v, bl);
265 ::decode(nonce_plus_one, bl);
268 WRITE_CLASS_ENCODER(CephXAuthorizeReply)
271 struct CephXAuthorizer : public AuthAuthorizer {
277 explicit CephXAuthorizer(CephContext *cct_)
278 : AuthAuthorizer(CEPH_AUTH_CEPHX), cct(cct_), nonce(0) {}
280 bool build_authorizer();
281 bool verify_reply(bufferlist::iterator& reply) override;
289 struct CephXTicketHandler {
291 CryptoKey session_key;
292 CephXTicketBlob ticket; // opaque to us
293 utime_t renew_after, expires;
296 CephXTicketHandler(CephContext *cct_, uint32_t service_id_)
297 : service_id(service_id_), have_key_flag(false), cct(cct_) { }
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;
306 bool need_key() const;
308 void invalidate_ticket() {
315 struct CephXTicketManager {
316 typedef map<uint32_t, CephXTicketHandler> tickets_map_t;
317 tickets_map_t tickets_map;
320 explicit CephXTicketManager(CephContext *cct_) : global_id(0), cct(cct_) {}
322 bool verify_service_ticket_reply(CryptoKey& principal_secret,
323 bufferlist::iterator& indata);
325 CephXTicketHandler& get_handler(uint32_t type) {
326 tickets_map_t::iterator i = tickets_map.find(type);
327 if (i != tickets_map.end())
329 CephXTicketHandler newTicketHandler(cct, type);
330 std::pair < tickets_map_t::iterator, bool > res =
331 tickets_map.insert(std::make_pair(type, newTicketHandler));
333 return res.first->second;
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);
348 struct CephXServiceTicket {
349 CryptoKey session_key;
352 void encode(bufferlist& bl) const {
354 ::encode(struct_v, bl);
355 ::encode(session_key, bl);
356 ::encode(validity, bl);
358 void decode(bufferlist::iterator& bl) {
360 ::decode(struct_v, bl);
361 ::decode(session_key, bl);
362 ::decode(validity, bl);
365 WRITE_CLASS_ENCODER(CephXServiceTicket)
368 struct CephXServiceTicketInfo {
370 CryptoKey session_key;
372 void encode(bufferlist& bl) const {
374 ::encode(struct_v, bl);
375 ::encode(ticket, bl);
376 ::encode(session_key, bl);
378 void decode(bufferlist::iterator& bl) {
380 ::decode(struct_v, bl);
381 ::decode(ticket, bl);
382 ::decode(session_key, bl);
385 WRITE_CLASS_ENCODER(CephXServiceTicketInfo)
387 struct CephXAuthorize {
389 void encode(bufferlist& bl) const {
391 ::encode(struct_v, bl);
394 void decode(bufferlist::iterator& bl) {
396 ::decode(struct_v, bl);
400 WRITE_CLASS_ENCODER(CephXAuthorize)
403 * Decode an extract ticket
405 bool cephx_decode_ticket(CephContext *cct, KeyStore *keys,
406 uint32_t service_id, CephXTicketBlob& ticket_blob,
407 CephXServiceTicketInfo& ticket_info);
410 * Verify authorizer and generate reply authorizer
412 extern bool cephx_verify_authorizer(CephContext *cct, KeyStore *keys,
413 bufferlist::iterator& indata,
414 CephXServiceTicketInfo& ticket_info, bufferlist& reply_bl);
422 * encode+encrypt macros
424 static constexpr uint64_t AUTH_ENC_MAGIC = 0xff009cad8826aa55ull;
426 template <typename T>
427 void decode_decrypt_enc_bl(CephContext *cct, T& t, CryptoKey key, bufferlist& bl_enc,
433 if (key.decrypt(cct, bl_enc, bl, &error) < 0)
436 bufferlist::iterator iter2 = bl.begin();
438 ::decode(struct_v, iter2);
439 ::decode(magic, iter2);
440 if (magic != AUTH_ENC_MAGIC) {
442 oss << "bad magic in decode_decrypt, " << magic << " != " << AUTH_ENC_MAGIC;
450 template <typename T>
451 void encode_encrypt_enc_bl(CephContext *cct, const T& t, const CryptoKey& key,
452 bufferlist& out, std::string &error)
456 ::encode(struct_v, bl);
457 uint64_t magic = AUTH_ENC_MAGIC;
461 key.encrypt(cct, bl, out, &error);
464 template <typename T>
465 int decode_decrypt(CephContext *cct, T& t, const CryptoKey& key,
466 bufferlist::iterator& iter, std::string &error)
470 ::decode(bl_enc, iter);
471 decode_decrypt_enc_bl(cct, t, key, bl_enc, error);
473 catch (buffer::error &e) {
474 error = "error decoding block for decryption";
477 return CEPHX_CRYPT_ERR;
481 template <typename T>
482 int encode_encrypt(CephContext *cct, const T& t, const CryptoKey& key,
483 bufferlist& out, std::string &error)
486 encode_encrypt_enc_bl(cct, t, key, bl_enc, error);
488 return CEPHX_CRYPT_ERR;
490 ::encode(bl_enc, out);