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
{
278 explicit CephXAuthorizer(CephContext
*cct_
)
279 : AuthAuthorizer(CEPH_AUTH_CEPHX
), cct(cct_
), nonce(0) {}
281 bool build_authorizer();
282 bool verify_reply(bufferlist::iterator
& reply
) override
;
283 bool add_challenge(CephContext
*cct
, bufferlist
& challenge
) override
;
291 struct CephXTicketHandler
{
293 CryptoKey session_key
;
294 CephXTicketBlob ticket
; // opaque to us
295 utime_t renew_after
, expires
;
298 CephXTicketHandler(CephContext
*cct_
, uint32_t service_id_
)
299 : service_id(service_id_
), have_key_flag(false), cct(cct_
) { }
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;
308 bool need_key() const;
310 void invalidate_ticket() {
317 struct CephXTicketManager
{
318 typedef map
<uint32_t, CephXTicketHandler
> tickets_map_t
;
319 tickets_map_t tickets_map
;
322 explicit CephXTicketManager(CephContext
*cct_
) : global_id(0), cct(cct_
) {}
324 bool verify_service_ticket_reply(CryptoKey
& principal_secret
,
325 bufferlist::iterator
& indata
);
327 CephXTicketHandler
& get_handler(uint32_t type
) {
328 tickets_map_t::iterator i
= tickets_map
.find(type
);
329 if (i
!= tickets_map
.end())
331 CephXTicketHandler
newTicketHandler(cct
, type
);
332 std::pair
< tickets_map_t::iterator
, bool > res
=
333 tickets_map
.insert(std::make_pair(type
, newTicketHandler
));
335 return res
.first
->second
;
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
);
350 struct CephXServiceTicket
{
351 CryptoKey session_key
;
354 void encode(bufferlist
& bl
) const {
356 ::encode(struct_v
, bl
);
357 ::encode(session_key
, bl
);
358 ::encode(validity
, bl
);
360 void decode(bufferlist::iterator
& bl
) {
362 ::decode(struct_v
, bl
);
363 ::decode(session_key
, bl
);
364 ::decode(validity
, bl
);
367 WRITE_CLASS_ENCODER(CephXServiceTicket
)
370 struct CephXServiceTicketInfo
{
372 CryptoKey session_key
;
374 void encode(bufferlist
& bl
) const {
376 ::encode(struct_v
, bl
);
377 ::encode(ticket
, bl
);
378 ::encode(session_key
, bl
);
380 void decode(bufferlist::iterator
& bl
) {
382 ::decode(struct_v
, bl
);
383 ::decode(ticket
, bl
);
384 ::decode(session_key
, bl
);
387 WRITE_CLASS_ENCODER(CephXServiceTicketInfo
)
389 struct CephXAuthorizeChallenge
: public AuthAuthorizerChallenge
{
390 uint64_t server_challenge
;
391 void encode(bufferlist
& bl
) const {
393 ::encode(struct_v
, bl
);
394 ::encode(server_challenge
, bl
);
396 void decode(bufferlist::iterator
& bl
) {
398 ::decode(struct_v
, bl
);
399 ::decode(server_challenge
, bl
);
402 WRITE_CLASS_ENCODER(CephXAuthorizeChallenge
)
404 struct CephXAuthorize
{
406 bool have_challenge
= false;
407 uint64_t server_challenge_plus_one
= 0;
408 void encode(bufferlist
& bl
) const {
410 ::encode(struct_v
, bl
);
412 ::encode(have_challenge
, bl
);
413 ::encode(server_challenge_plus_one
, bl
);
415 void decode(bufferlist::iterator
& bl
) {
417 ::decode(struct_v
, bl
);
420 ::decode(have_challenge
, bl
);
421 ::decode(server_challenge_plus_one
, bl
);
426 WRITE_CLASS_ENCODER(CephXAuthorize
)
429 * Decode an extract ticket
431 bool cephx_decode_ticket(CephContext
*cct
, KeyStore
*keys
,
432 uint32_t service_id
, CephXTicketBlob
& ticket_blob
,
433 CephXServiceTicketInfo
& ticket_info
);
436 * Verify authorizer and generate reply authorizer
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
);
451 * encode+encrypt macros
453 static constexpr uint64_t AUTH_ENC_MAGIC
= 0xff009cad8826aa55ull
;
455 template <typename T
>
456 void decode_decrypt_enc_bl(CephContext
*cct
, T
& t
, CryptoKey key
, bufferlist
& bl_enc
,
462 if (key
.decrypt(cct
, bl_enc
, bl
, &error
) < 0)
465 bufferlist::iterator iter2
= bl
.begin();
467 ::decode(struct_v
, iter2
);
468 ::decode(magic
, iter2
);
469 if (magic
!= AUTH_ENC_MAGIC
) {
471 oss
<< "bad magic in decode_decrypt, " << magic
<< " != " << AUTH_ENC_MAGIC
;
479 template <typename T
>
480 void encode_encrypt_enc_bl(CephContext
*cct
, const T
& t
, const CryptoKey
& key
,
481 bufferlist
& out
, std::string
&error
)
485 ::encode(struct_v
, bl
);
486 uint64_t magic
= AUTH_ENC_MAGIC
;
490 key
.encrypt(cct
, bl
, out
, &error
);
493 template <typename T
>
494 int decode_decrypt(CephContext
*cct
, T
& t
, const CryptoKey
& key
,
495 bufferlist::iterator
& iter
, std::string
&error
)
499 ::decode(bl_enc
, iter
);
500 decode_decrypt_enc_bl(cct
, t
, key
, bl_enc
, error
);
502 catch (buffer::error
&e
) {
503 error
= "error decoding block for decryption";
506 return CEPHX_CRYPT_ERR
;
510 template <typename T
>
511 int encode_encrypt(CephContext
*cct
, const T
& t
, const CryptoKey
& key
,
512 bufferlist
& out
, std::string
&error
)
515 encode_encrypt_enc_bl(cct
, t
, key
, bl_enc
, error
);
517 return CEPHX_CRYPT_ERR
;
519 ::encode(bl_enc
, out
);