X-Git-Url: https://gerrit.opnfv.org/gerrit/gitweb?a=blobdiff_plain;f=src%2Fceph%2Fsrc%2Fauth%2Fcephx%2FCephxProtocol.h;fp=src%2Fceph%2Fsrc%2Fauth%2Fcephx%2FCephxProtocol.h;h=c82206989906155ba8400187ee87535dbc2ff627;hb=812ff6ca9fcd3e629e49d4328905f33eee8ca3f5;hp=0000000000000000000000000000000000000000;hpb=15280273faafb77777eab341909a3f495cf248d9;p=stor4nfv.git diff --git a/src/ceph/src/auth/cephx/CephxProtocol.h b/src/ceph/src/auth/cephx/CephxProtocol.h new file mode 100644 index 0000000..c822069 --- /dev/null +++ b/src/ceph/src/auth/cephx/CephxProtocol.h @@ -0,0 +1,495 @@ +// -*- mode:C++; tab-width:8; c-basic-offset:2; indent-tabs-mode:t -*- +// vim: ts=8 sw=2 smarttab +/* + * Ceph - scalable distributed file system + * + * Copyright (C) 2004-2009 Sage Weil + * + * This is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License version 2.1, as published by the Free Software + * Foundation. See file COPYING. + * + */ + +#ifndef CEPH_CEPHXPROTOCOL_H +#define CEPH_CEPHXPROTOCOL_H + +/* + Ceph X protocol + + First, the principal has to authenticate with the authenticator. A + shared-secret mechanism is being used, and the negotitaion goes like this: + + A = Authenticator + P = Principle + S = Service + + 1. Obtaining principal/auth session key + + (Authenticate Request) + p->a : principal, principal_addr. authenticate me! + + ...authenticator does lookup in database... + + a->p : A= {principal/auth session key, validity}^principal_secret (*) + B= {principal ticket, validity, principal/auth session key}^authsecret + + + [principal/auth session key, validity] = service ticket + [principal ticket, validity, principal/auth session key] = service ticket info + + (*) annotation: ^ signifies 'encrypted by' + + At this point, if is genuine, the principal should have the principal/auth + session key at hand. The next step would be to request an authorization to + use some other service: + + 2. Obtaining principal/service session key + + p->a : B, {principal_addr, timestamp}^principal/auth session key. authorize + me! + a->p : E= {service ticket}^svcsecret + F= {principal/service session key, validity}^principal/auth session key + + principal_addr, timestamp = authenticator + + service ticket = principal name, client network address, validity, principal/service session key + + Note that steps 1 and 2 are pretty much the same thing; contacting the + authenticator and requesting for a key. + + Following this the principal should have a principal/service session key that + could be used later on for creating a session: + + 3. Opening a session to a service + + p->s : E + {principal_addr, timestamp}^principal/service session key + s->p : {timestamp+1}^principal/service/session key + + timestamp+1 = reply authenticator + + Now, the principal is fully authenticated with the service. So, logically we + have 2 main actions here. The first one would be to obtain a session key to + the service (steps 1 and 2), and the second one would be to authenticate with + the service, using that ticket. +*/ + +/* authenticate requests */ +#define CEPHX_GET_AUTH_SESSION_KEY 0x0100 +#define CEPHX_GET_PRINCIPAL_SESSION_KEY 0x0200 +#define CEPHX_GET_ROTATING_KEY 0x0400 + +#define CEPHX_REQUEST_TYPE_MASK 0x0F00 +#define CEPHX_CRYPT_ERR 1 + +#include "auth/Auth.h" +#include +#include + +class CephContext; + +/* + * Authentication + */ + +// initial server -> client challenge +struct CephXServerChallenge { + uint64_t server_challenge; + + void encode(bufferlist& bl) const { + __u8 struct_v = 1; + ::encode(struct_v, bl); + ::encode(server_challenge, bl); + } + void decode(bufferlist::iterator& bl) { + __u8 struct_v; + ::decode(struct_v, bl); + ::decode(server_challenge, bl); + } +}; +WRITE_CLASS_ENCODER(CephXServerChallenge) + + +// request/reply headers, for subsequent exchanges. + +struct CephXRequestHeader { + __u16 request_type; + + void encode(bufferlist& bl) const { + ::encode(request_type, bl); + } + void decode(bufferlist::iterator& bl) { + ::decode(request_type, bl); + } +}; +WRITE_CLASS_ENCODER(CephXRequestHeader) + +struct CephXResponseHeader { + uint16_t request_type; + int32_t status; + + void encode(bufferlist& bl) const { + ::encode(request_type, bl); + ::encode(status, bl); + } + void decode(bufferlist::iterator& bl) { + ::decode(request_type, bl); + ::decode(status, bl); + } +}; +WRITE_CLASS_ENCODER(CephXResponseHeader) + +struct CephXTicketBlob { + uint64_t secret_id; + bufferlist blob; + + CephXTicketBlob() : secret_id(0) {} + + void encode(bufferlist& bl) const { + __u8 struct_v = 1; + ::encode(struct_v, bl); + ::encode(secret_id, bl); + ::encode(blob, bl); + } + + void decode(bufferlist::iterator& bl) { + __u8 struct_v; + ::decode(struct_v, bl); + ::decode(secret_id, bl); + ::decode(blob, bl); + } +}; +WRITE_CLASS_ENCODER(CephXTicketBlob) + +// client -> server response to challenge +struct CephXAuthenticate { + uint64_t client_challenge; + uint64_t key; + CephXTicketBlob old_ticket; + + void encode(bufferlist& bl) const { + __u8 struct_v = 1; + ::encode(struct_v, bl); + ::encode(client_challenge, bl); + ::encode(key, bl); + ::encode(old_ticket, bl); + } + void decode(bufferlist::iterator& bl) { + __u8 struct_v; + ::decode(struct_v, bl); + ::decode(client_challenge, bl); + ::decode(key, bl); + ::decode(old_ticket, bl); + } +}; +WRITE_CLASS_ENCODER(CephXAuthenticate) + +struct CephXChallengeBlob { + uint64_t server_challenge, client_challenge; + + void encode(bufferlist& bl) const { + ::encode(server_challenge, bl); + ::encode(client_challenge, bl); + } + void decode(bufferlist::iterator& bl) { + ::decode(server_challenge, bl); + ::decode(client_challenge, bl); + } +}; +WRITE_CLASS_ENCODER(CephXChallengeBlob) + +void cephx_calc_client_server_challenge(CephContext *cct, + CryptoKey& secret, uint64_t server_challenge, uint64_t client_challenge, + uint64_t *key, std::string &error); + + +/* + * getting service tickets + */ +struct CephXSessionAuthInfo { + uint32_t service_id; + uint64_t secret_id; + AuthTicket ticket; + CryptoKey session_key; + CryptoKey service_secret; + utime_t validity; +}; + + +extern bool cephx_build_service_ticket_blob(CephContext *cct, + CephXSessionAuthInfo& ticket_info, CephXTicketBlob& blob); + +extern void cephx_build_service_ticket_request(CephContext *cct, + uint32_t keys, + bufferlist& request); + +extern bool cephx_build_service_ticket_reply(CephContext *cct, + CryptoKey& principal_secret, + vector ticket_info, + bool should_encrypt_ticket, + CryptoKey& ticket_enc_key, + bufferlist& reply); + +struct CephXServiceTicketRequest { + uint32_t keys; + + void encode(bufferlist& bl) const { + __u8 struct_v = 1; + ::encode(struct_v, bl); + ::encode(keys, bl); + } + void decode(bufferlist::iterator& bl) { + __u8 struct_v; + ::decode(struct_v, bl); + ::decode(keys, bl); + } +}; +WRITE_CLASS_ENCODER(CephXServiceTicketRequest) + + +/* + * Authorize + */ + +struct CephXAuthorizeReply { + uint64_t nonce_plus_one; + void encode(bufferlist& bl) const { + __u8 struct_v = 1; + ::encode(struct_v, bl); + ::encode(nonce_plus_one, bl); + } + void decode(bufferlist::iterator& bl) { + __u8 struct_v; + ::decode(struct_v, bl); + ::decode(nonce_plus_one, bl); + } +}; +WRITE_CLASS_ENCODER(CephXAuthorizeReply) + + +struct CephXAuthorizer : public AuthAuthorizer { +private: + CephContext *cct; +public: + uint64_t nonce; + + explicit CephXAuthorizer(CephContext *cct_) + : AuthAuthorizer(CEPH_AUTH_CEPHX), cct(cct_), nonce(0) {} + + bool build_authorizer(); + bool verify_reply(bufferlist::iterator& reply) override; +}; + + + +/* + * TicketHandler + */ +struct CephXTicketHandler { + uint32_t service_id; + CryptoKey session_key; + CephXTicketBlob ticket; // opaque to us + utime_t renew_after, expires; + bool have_key_flag; + + CephXTicketHandler(CephContext *cct_, uint32_t service_id_) + : service_id(service_id_), have_key_flag(false), cct(cct_) { } + + // to build our ServiceTicket + bool verify_service_ticket_reply(CryptoKey& principal_secret, + bufferlist::iterator& indata); + // to access the service + CephXAuthorizer *build_authorizer(uint64_t global_id) const; + + bool have_key(); + bool need_key() const; + + void invalidate_ticket() { + have_key_flag = 0; + } +private: + CephContext *cct; +}; + +struct CephXTicketManager { + typedef map tickets_map_t; + tickets_map_t tickets_map; + uint64_t global_id; + + explicit CephXTicketManager(CephContext *cct_) : global_id(0), cct(cct_) {} + + bool verify_service_ticket_reply(CryptoKey& principal_secret, + bufferlist::iterator& indata); + + CephXTicketHandler& get_handler(uint32_t type) { + tickets_map_t::iterator i = tickets_map.find(type); + if (i != tickets_map.end()) + return i->second; + CephXTicketHandler newTicketHandler(cct, type); + std::pair < tickets_map_t::iterator, bool > res = + tickets_map.insert(std::make_pair(type, newTicketHandler)); + assert(res.second); + return res.first->second; + } + CephXAuthorizer *build_authorizer(uint32_t service_id) const; + bool have_key(uint32_t service_id); + bool need_key(uint32_t service_id) const; + void set_have_need_key(uint32_t service_id, uint32_t& have, uint32_t& need); + void validate_tickets(uint32_t mask, uint32_t& have, uint32_t& need); + void invalidate_ticket(uint32_t service_id); + +private: + CephContext *cct; +}; + + +/* A */ +struct CephXServiceTicket { + CryptoKey session_key; + utime_t validity; + + void encode(bufferlist& bl) const { + __u8 struct_v = 1; + ::encode(struct_v, bl); + ::encode(session_key, bl); + ::encode(validity, bl); + } + void decode(bufferlist::iterator& bl) { + __u8 struct_v; + ::decode(struct_v, bl); + ::decode(session_key, bl); + ::decode(validity, bl); + } +}; +WRITE_CLASS_ENCODER(CephXServiceTicket) + +/* B */ +struct CephXServiceTicketInfo { + AuthTicket ticket; + CryptoKey session_key; + + void encode(bufferlist& bl) const { + __u8 struct_v = 1; + ::encode(struct_v, bl); + ::encode(ticket, bl); + ::encode(session_key, bl); + } + void decode(bufferlist::iterator& bl) { + __u8 struct_v; + ::decode(struct_v, bl); + ::decode(ticket, bl); + ::decode(session_key, bl); + } +}; +WRITE_CLASS_ENCODER(CephXServiceTicketInfo) + +struct CephXAuthorize { + uint64_t nonce; + void encode(bufferlist& bl) const { + __u8 struct_v = 1; + ::encode(struct_v, bl); + ::encode(nonce, bl); + } + void decode(bufferlist::iterator& bl) { + __u8 struct_v; + ::decode(struct_v, bl); + ::decode(nonce, bl); + } +}; +WRITE_CLASS_ENCODER(CephXAuthorize) + +/* + * Decode an extract ticket + */ +bool cephx_decode_ticket(CephContext *cct, KeyStore *keys, + uint32_t service_id, CephXTicketBlob& ticket_blob, + CephXServiceTicketInfo& ticket_info); + +/* + * Verify authorizer and generate reply authorizer + */ +extern bool cephx_verify_authorizer(CephContext *cct, KeyStore *keys, + bufferlist::iterator& indata, + CephXServiceTicketInfo& ticket_info, bufferlist& reply_bl); + + + + + + +/* + * encode+encrypt macros + */ +static constexpr uint64_t AUTH_ENC_MAGIC = 0xff009cad8826aa55ull; + +template +void decode_decrypt_enc_bl(CephContext *cct, T& t, CryptoKey key, bufferlist& bl_enc, + std::string &error) +{ + uint64_t magic; + bufferlist bl; + + if (key.decrypt(cct, bl_enc, bl, &error) < 0) + return; + + bufferlist::iterator iter2 = bl.begin(); + __u8 struct_v; + ::decode(struct_v, iter2); + ::decode(magic, iter2); + if (magic != AUTH_ENC_MAGIC) { + ostringstream oss; + oss << "bad magic in decode_decrypt, " << magic << " != " << AUTH_ENC_MAGIC; + error = oss.str(); + return; + } + + ::decode(t, iter2); +} + +template +void encode_encrypt_enc_bl(CephContext *cct, const T& t, const CryptoKey& key, + bufferlist& out, std::string &error) +{ + bufferlist bl; + __u8 struct_v = 1; + ::encode(struct_v, bl); + uint64_t magic = AUTH_ENC_MAGIC; + ::encode(magic, bl); + ::encode(t, bl); + + key.encrypt(cct, bl, out, &error); +} + +template +int decode_decrypt(CephContext *cct, T& t, const CryptoKey& key, + bufferlist::iterator& iter, std::string &error) +{ + bufferlist bl_enc; + try { + ::decode(bl_enc, iter); + decode_decrypt_enc_bl(cct, t, key, bl_enc, error); + } + catch (buffer::error &e) { + error = "error decoding block for decryption"; + } + if (!error.empty()) + return CEPHX_CRYPT_ERR; + return 0; +} + +template +int encode_encrypt(CephContext *cct, const T& t, const CryptoKey& key, + bufferlist& out, std::string &error) +{ + bufferlist bl_enc; + encode_encrypt_enc_bl(cct, t, key, bl_enc, error); + if (!error.empty()){ + return CEPHX_CRYPT_ERR; + } + ::encode(bl_enc, out); + return 0; +} + + +#endif