1 2#include "ceph_debug.h" 3 4#include <linux/err.h> 5#include <linux/module.h> 6#include <linux/random.h> 7#include <linux/slab.h> 8 9#include "auth_x.h" 10#include "auth_x_protocol.h" 11#include "crypto.h" 12#include "auth.h" 13#include "decode.h" 14 15#define TEMP_TICKET_BUF_LEN 256 16 17static void ceph_x_validate_tickets(struct ceph_auth_client *ac, int *pneed); 18 19static int ceph_x_is_authenticated(struct ceph_auth_client *ac) 20{ 21 struct ceph_x_info *xi = ac->private; 22 int need; 23 24 ceph_x_validate_tickets(ac, &need); 25 dout("ceph_x_is_authenticated want=%d need=%d have=%d\n", 26 ac->want_keys, need, xi->have_keys); 27 return (ac->want_keys & xi->have_keys) == ac->want_keys; 28} 29 30static int ceph_x_should_authenticate(struct ceph_auth_client *ac) 31{ 32 struct ceph_x_info *xi = ac->private; 33 int need; 34 35 ceph_x_validate_tickets(ac, &need); 36 dout("ceph_x_should_authenticate want=%d need=%d have=%d\n", 37 ac->want_keys, need, xi->have_keys); 38 return need != 0; 39} 40 41static int ceph_x_encrypt_buflen(int ilen) 42{ 43 return sizeof(struct ceph_x_encrypt_header) + ilen + 16 + 44 sizeof(u32); 45} 46 47static int ceph_x_encrypt(struct ceph_crypto_key *secret, 48 void *ibuf, int ilen, void *obuf, size_t olen) 49{ 50 struct ceph_x_encrypt_header head = { 51 .struct_v = 1, 52 .magic = cpu_to_le64(CEPHX_ENC_MAGIC) 53 }; 54 size_t len = olen - sizeof(u32); 55 int ret; 56 57 ret = ceph_encrypt2(secret, obuf + sizeof(u32), &len, 58 &head, sizeof(head), ibuf, ilen); 59 if (ret) 60 return ret; 61 ceph_encode_32(&obuf, len); 62 return len + sizeof(u32); 63} 64 65static int ceph_x_decrypt(struct ceph_crypto_key *secret, 66 void **p, void *end, void *obuf, size_t olen) 67{ 68 struct ceph_x_encrypt_header head; 69 size_t head_len = sizeof(head); 70 int len, ret; 71 72 len = ceph_decode_32(p); 73 if (*p + len > end) 74 return -EINVAL; 75 76 dout("ceph_x_decrypt len %d\n", len); 77 ret = ceph_decrypt2(secret, &head, &head_len, obuf, &olen, 78 *p, len); 79 if (ret) 80 return ret; 81 if (head.struct_v != 1 || le64_to_cpu(head.magic) != CEPHX_ENC_MAGIC) 82 return -EPERM; 83 *p += len; 84 return olen; 85} 86 87/* 88 * get existing (or insert new) ticket handler 89 */ 90static struct ceph_x_ticket_handler * 91get_ticket_handler(struct ceph_auth_client *ac, int service) 92{ 93 struct ceph_x_ticket_handler *th; 94 struct ceph_x_info *xi = ac->private; 95 struct rb_node *parent = NULL, **p = &xi->ticket_handlers.rb_node; 96 97 while (*p) { 98 parent = *p; 99 th = rb_entry(parent, struct ceph_x_ticket_handler, node); 100 if (service < th->service) 101 p = &(*p)->rb_left; 102 else if (service > th->service) 103 p = &(*p)->rb_right; 104 else 105 return th; 106 } 107 108 /* add it */ 109 th = kzalloc(sizeof(*th), GFP_NOFS); 110 if (!th) 111 return ERR_PTR(-ENOMEM); 112 th->service = service; 113 rb_link_node(&th->node, parent, p); 114 rb_insert_color(&th->node, &xi->ticket_handlers); 115 return th; 116} 117 118static void remove_ticket_handler(struct ceph_auth_client *ac, 119 struct ceph_x_ticket_handler *th) 120{ 121 struct ceph_x_info *xi = ac->private; 122 123 dout("remove_ticket_handler %p %d\n", th, th->service); 124 rb_erase(&th->node, &xi->ticket_handlers); 125 ceph_crypto_key_destroy(&th->session_key); 126 if (th->ticket_blob) 127 ceph_buffer_put(th->ticket_blob); 128 kfree(th); 129} 130 131static int ceph_x_proc_ticket_reply(struct ceph_auth_client *ac, 132 struct ceph_crypto_key *secret, 133 void *buf, void *end) 134{ 135 struct ceph_x_info *xi = ac->private; 136 int num; 137 void *p = buf; 138 int ret; 139 char *dbuf; 140 char *ticket_buf; 141 u8 reply_struct_v; 142 143 dbuf = kmalloc(TEMP_TICKET_BUF_LEN, GFP_NOFS); 144 if (!dbuf) 145 return -ENOMEM; 146 147 ret = -ENOMEM; 148 ticket_buf = kmalloc(TEMP_TICKET_BUF_LEN, GFP_NOFS); 149 if (!ticket_buf) 150 goto out_dbuf; 151 152 ceph_decode_need(&p, end, 1 + sizeof(u32), bad); 153 reply_struct_v = ceph_decode_8(&p); 154 if (reply_struct_v != 1) 155 goto bad; 156 num = ceph_decode_32(&p); 157 dout("%d tickets\n", num); 158 while (num--) { 159 int type; 160 u8 tkt_struct_v, blob_struct_v; 161 struct ceph_x_ticket_handler *th; 162 void *dp, *dend; 163 int dlen; 164 char is_enc; 165 struct timespec validity; 166 struct ceph_crypto_key old_key; 167 void *tp, *tpend; 168 struct ceph_timespec new_validity; 169 struct ceph_crypto_key new_session_key; 170 struct ceph_buffer *new_ticket_blob; 171 unsigned long new_expires, new_renew_after; 172 u64 new_secret_id; 173 174 ceph_decode_need(&p, end, sizeof(u32) + 1, bad); 175 176 type = ceph_decode_32(&p); 177 dout(" ticket type %d %s\n", type, ceph_entity_type_name(type)); 178 179 tkt_struct_v = ceph_decode_8(&p); 180 if (tkt_struct_v != 1) 181 goto bad; 182 183 th = get_ticket_handler(ac, type); 184 if (IS_ERR(th)) { 185 ret = PTR_ERR(th); 186 goto out; 187 } 188 189 /* blob for me */ 190 dlen = ceph_x_decrypt(secret, &p, end, dbuf, 191 TEMP_TICKET_BUF_LEN); 192 if (dlen <= 0) { 193 ret = dlen; 194 goto out; 195 } 196 dout(" decrypted %d bytes\n", dlen); 197 dend = dbuf + dlen; 198 dp = dbuf; 199 200 tkt_struct_v = ceph_decode_8(&dp); 201 if (tkt_struct_v != 1) 202 goto bad; 203 204 memcpy(&old_key, &th->session_key, sizeof(old_key)); 205 ret = ceph_crypto_key_decode(&new_session_key, &dp, dend); 206 if (ret) 207 goto out; 208 209 ceph_decode_copy(&dp, &new_validity, sizeof(new_validity)); 210 ceph_decode_timespec(&validity, &new_validity); 211 new_expires = get_seconds() + validity.tv_sec; 212 new_renew_after = new_expires - (validity.tv_sec / 4); 213 dout(" expires=%lu renew_after=%lu\n", new_expires, 214 new_renew_after); 215 216 /* ticket blob for service */ 217 ceph_decode_8_safe(&p, end, is_enc, bad); 218 tp = ticket_buf; 219 if (is_enc) { 220 /* encrypted */ 221 dout(" encrypted ticket\n"); 222 dlen = ceph_x_decrypt(&old_key, &p, end, ticket_buf, 223 TEMP_TICKET_BUF_LEN); 224 if (dlen < 0) { 225 ret = dlen; 226 goto out; 227 } 228 dlen = ceph_decode_32(&tp); 229 } else { 230 /* unencrypted */ 231 ceph_decode_32_safe(&p, end, dlen, bad); 232 ceph_decode_need(&p, end, dlen, bad); 233 ceph_decode_copy(&p, ticket_buf, dlen); 234 } 235 tpend = tp + dlen; 236 dout(" ticket blob is %d bytes\n", dlen); 237 ceph_decode_need(&tp, tpend, 1 + sizeof(u64), bad); 238 blob_struct_v = ceph_decode_8(&tp); 239 new_secret_id = ceph_decode_64(&tp); 240 ret = ceph_decode_buffer(&new_ticket_blob, &tp, tpend); 241 if (ret) 242 goto out; 243 244 /* all is well, update our ticket */ 245 ceph_crypto_key_destroy(&th->session_key); 246 if (th->ticket_blob) 247 ceph_buffer_put(th->ticket_blob); 248 th->session_key = new_session_key; 249 th->ticket_blob = new_ticket_blob; 250 th->validity = new_validity; 251 th->secret_id = new_secret_id; 252 th->expires = new_expires; 253 th->renew_after = new_renew_after; 254 dout(" got ticket service %d (%s) secret_id %lld len %d\n", 255 type, ceph_entity_type_name(type), th->secret_id, 256 (int)th->ticket_blob->vec.iov_len); 257 xi->have_keys |= th->service; 258 } 259 260 ret = 0; 261out: 262 kfree(ticket_buf); 263out_dbuf: 264 kfree(dbuf); 265 return ret; 266 267bad: 268 ret = -EINVAL; 269 goto out; 270} 271 272static int ceph_x_build_authorizer(struct ceph_auth_client *ac, 273 struct ceph_x_ticket_handler *th, 274 struct ceph_x_authorizer *au) 275{ 276 int maxlen; 277 struct ceph_x_authorize_a *msg_a; 278 struct ceph_x_authorize_b msg_b; 279 void *p, *end; 280 int ret; 281 int ticket_blob_len = 282 (th->ticket_blob ? th->ticket_blob->vec.iov_len : 0); 283 284 dout("build_authorizer for %s %p\n", 285 ceph_entity_type_name(th->service), au); 286 287 maxlen = sizeof(*msg_a) + sizeof(msg_b) + 288 ceph_x_encrypt_buflen(ticket_blob_len); 289 dout(" need len %d\n", maxlen); 290 if (au->buf && au->buf->alloc_len < maxlen) { 291 ceph_buffer_put(au->buf); 292 au->buf = NULL; 293 } 294 if (!au->buf) { 295 au->buf = ceph_buffer_new(maxlen, GFP_NOFS); 296 if (!au->buf) 297 return -ENOMEM; 298 } 299 au->service = th->service; 300 301 msg_a = au->buf->vec.iov_base; 302 msg_a->struct_v = 1; 303 msg_a->global_id = cpu_to_le64(ac->global_id); 304 msg_a->service_id = cpu_to_le32(th->service); 305 msg_a->ticket_blob.struct_v = 1; 306 msg_a->ticket_blob.secret_id = cpu_to_le64(th->secret_id); 307 msg_a->ticket_blob.blob_len = cpu_to_le32(ticket_blob_len); 308 if (ticket_blob_len) { 309 memcpy(msg_a->ticket_blob.blob, th->ticket_blob->vec.iov_base, 310 th->ticket_blob->vec.iov_len); 311 } 312 dout(" th %p secret_id %lld %lld\n", th, th->secret_id, 313 le64_to_cpu(msg_a->ticket_blob.secret_id)); 314 315 p = msg_a + 1; 316 p += ticket_blob_len; 317 end = au->buf->vec.iov_base + au->buf->vec.iov_len; 318 319 get_random_bytes(&au->nonce, sizeof(au->nonce)); 320 msg_b.struct_v = 1; 321 msg_b.nonce = cpu_to_le64(au->nonce); 322 ret = ceph_x_encrypt(&th->session_key, &msg_b, sizeof(msg_b), 323 p, end - p); 324 if (ret < 0) 325 goto out_buf; 326 p += ret; 327 au->buf->vec.iov_len = p - au->buf->vec.iov_base; 328 dout(" built authorizer nonce %llx len %d\n", au->nonce, 329 (int)au->buf->vec.iov_len); 330 BUG_ON(au->buf->vec.iov_len > maxlen); 331 return 0; 332 333out_buf: 334 ceph_buffer_put(au->buf); 335 au->buf = NULL; 336 return ret; 337} 338 339static int ceph_x_encode_ticket(struct ceph_x_ticket_handler *th, 340 void **p, void *end) 341{ 342 ceph_decode_need(p, end, 1 + sizeof(u64), bad); 343 ceph_encode_8(p, 1); 344 ceph_encode_64(p, th->secret_id); 345 if (th->ticket_blob) { 346 const char *buf = th->ticket_blob->vec.iov_base; 347 u32 len = th->ticket_blob->vec.iov_len; 348 349 ceph_encode_32_safe(p, end, len, bad); 350 ceph_encode_copy_safe(p, end, buf, len, bad); 351 } else { 352 ceph_encode_32_safe(p, end, 0, bad); 353 } 354 355 return 0; 356bad: 357 return -ERANGE; 358} 359 360static void ceph_x_validate_tickets(struct ceph_auth_client *ac, int *pneed) 361{ 362 int want = ac->want_keys; 363 struct ceph_x_info *xi = ac->private; 364 int service; 365 366 *pneed = ac->want_keys & ~(xi->have_keys); 367 368 for (service = 1; service <= want; service <<= 1) { 369 struct ceph_x_ticket_handler *th; 370 371 if (!(ac->want_keys & service)) 372 continue; 373 374 if (*pneed & service) 375 continue; 376 377 th = get_ticket_handler(ac, service); 378 379 if (IS_ERR(th)) { 380 *pneed |= service; 381 continue; 382 } 383 384 if (get_seconds() >= th->renew_after) 385 *pneed |= service; 386 if (get_seconds() >= th->expires) 387 xi->have_keys &= ~service; 388 } 389} 390 391 392static int ceph_x_build_request(struct ceph_auth_client *ac, 393 void *buf, void *end) 394{ 395 struct ceph_x_info *xi = ac->private; 396 int need; 397 struct ceph_x_request_header *head = buf; 398 int ret; 399 struct ceph_x_ticket_handler *th = 400 get_ticket_handler(ac, CEPH_ENTITY_TYPE_AUTH); 401 402 if (IS_ERR(th)) 403 return PTR_ERR(th); 404 405 ceph_x_validate_tickets(ac, &need); 406 407 dout("build_request want %x have %x need %x\n", 408 ac->want_keys, xi->have_keys, need); 409 410 if (need & CEPH_ENTITY_TYPE_AUTH) { 411 struct ceph_x_authenticate *auth = (void *)(head + 1); 412 void *p = auth + 1; 413 struct ceph_x_challenge_blob tmp; 414 char tmp_enc[40]; 415 u64 *u; 416 417 if (p > end) 418 return -ERANGE; 419 420 dout(" get_auth_session_key\n"); 421 head->op = cpu_to_le16(CEPHX_GET_AUTH_SESSION_KEY); 422 423 /* encrypt and hash */ 424 get_random_bytes(&auth->client_challenge, sizeof(u64)); 425 tmp.client_challenge = auth->client_challenge; 426 tmp.server_challenge = cpu_to_le64(xi->server_challenge); 427 ret = ceph_x_encrypt(&xi->secret, &tmp, sizeof(tmp), 428 tmp_enc, sizeof(tmp_enc)); 429 if (ret < 0) 430 return ret; 431 432 auth->struct_v = 1; 433 auth->key = 0; 434 for (u = (u64 *)tmp_enc; u + 1 <= (u64 *)(tmp_enc + ret); u++) 435 auth->key ^= *(__le64 *)u; 436 dout(" server_challenge %llx client_challenge %llx key %llx\n", 437 xi->server_challenge, le64_to_cpu(auth->client_challenge), 438 le64_to_cpu(auth->key)); 439 440 /* now encode the old ticket if exists */ 441 ret = ceph_x_encode_ticket(th, &p, end); 442 if (ret < 0) 443 return ret; 444 445 return p - buf; 446 } 447 448 if (need) { 449 void *p = head + 1; 450 struct ceph_x_service_ticket_request *req; 451 452 if (p > end) 453 return -ERANGE; 454 head->op = cpu_to_le16(CEPHX_GET_PRINCIPAL_SESSION_KEY); 455 456 ret = ceph_x_build_authorizer(ac, th, &xi->auth_authorizer); 457 if (ret) 458 return ret; 459 ceph_encode_copy(&p, xi->auth_authorizer.buf->vec.iov_base, 460 xi->auth_authorizer.buf->vec.iov_len); 461 462 req = p; 463 req->keys = cpu_to_le32(need); 464 p += sizeof(*req); 465 return p - buf; 466 } 467 468 return 0; 469} 470 471static int ceph_x_handle_reply(struct ceph_auth_client *ac, int result, 472 void *buf, void *end) 473{ 474 struct ceph_x_info *xi = ac->private; 475 struct ceph_x_reply_header *head = buf; 476 struct ceph_x_ticket_handler *th; 477 int len = end - buf; 478 int op; 479 int ret; 480 481 if (result) 482 return result; 483 484 if (xi->starting) { 485 /* it's a hello */ 486 struct ceph_x_server_challenge *sc = buf; 487 488 if (len != sizeof(*sc)) 489 return -EINVAL; 490 xi->server_challenge = le64_to_cpu(sc->server_challenge); 491 dout("handle_reply got server challenge %llx\n", 492 xi->server_challenge); 493 xi->starting = false; 494 xi->have_keys &= ~CEPH_ENTITY_TYPE_AUTH; 495 return -EAGAIN; 496 } 497 498 op = le16_to_cpu(head->op); 499 result = le32_to_cpu(head->result); 500 dout("handle_reply op %d result %d\n", op, result); 501 switch (op) { 502 case CEPHX_GET_AUTH_SESSION_KEY: 503 /* verify auth key */ 504 ret = ceph_x_proc_ticket_reply(ac, &xi->secret, 505 buf + sizeof(*head), end); 506 break; 507 508 case CEPHX_GET_PRINCIPAL_SESSION_KEY: 509 th = get_ticket_handler(ac, CEPH_ENTITY_TYPE_AUTH); 510 if (IS_ERR(th)) 511 return PTR_ERR(th); 512 ret = ceph_x_proc_ticket_reply(ac, &th->session_key, 513 buf + sizeof(*head), end); 514 break; 515 516 default: 517 return -EINVAL; 518 } 519 if (ret) 520 return ret; 521 if (ac->want_keys == xi->have_keys) 522 return 0; 523 return -EAGAIN; 524} 525 526static int ceph_x_create_authorizer( 527 struct ceph_auth_client *ac, int peer_type, 528 struct ceph_authorizer **a, 529 void **buf, size_t *len, 530 void **reply_buf, size_t *reply_len) 531{ 532 struct ceph_x_authorizer *au; 533 struct ceph_x_ticket_handler *th; 534 int ret; 535 536 th = get_ticket_handler(ac, peer_type); 537 if (IS_ERR(th)) 538 return PTR_ERR(th); 539 540 au = kzalloc(sizeof(*au), GFP_NOFS); 541 if (!au) 542 return -ENOMEM; 543 544 ret = ceph_x_build_authorizer(ac, th, au); 545 if (ret) { 546 kfree(au); 547 return ret; 548 } 549 550 *a = (struct ceph_authorizer *)au; 551 *buf = au->buf->vec.iov_base; 552 *len = au->buf->vec.iov_len; 553 *reply_buf = au->reply_buf; 554 *reply_len = sizeof(au->reply_buf); 555 return 0; 556} 557 558static int ceph_x_verify_authorizer_reply(struct ceph_auth_client *ac, 559 struct ceph_authorizer *a, size_t len) 560{ 561 struct ceph_x_authorizer *au = (void *)a; 562 struct ceph_x_ticket_handler *th; 563 int ret = 0; 564 struct ceph_x_authorize_reply reply; 565 void *p = au->reply_buf; 566 void *end = p + sizeof(au->reply_buf); 567 568 th = get_ticket_handler(ac, au->service); 569 if (IS_ERR(th)) 570 return PTR_ERR(th); 571 ret = ceph_x_decrypt(&th->session_key, &p, end, &reply, sizeof(reply)); 572 if (ret < 0) 573 return ret; 574 if (ret != sizeof(reply)) 575 return -EPERM; 576 577 if (au->nonce + 1 != le64_to_cpu(reply.nonce_plus_one)) 578 ret = -EPERM; 579 else 580 ret = 0; 581 dout("verify_authorizer_reply nonce %llx got %llx ret %d\n", 582 au->nonce, le64_to_cpu(reply.nonce_plus_one), ret); 583 return ret; 584} 585 586static void ceph_x_destroy_authorizer(struct ceph_auth_client *ac, 587 struct ceph_authorizer *a) 588{ 589 struct ceph_x_authorizer *au = (void *)a; 590 591 ceph_buffer_put(au->buf); 592 kfree(au); 593} 594 595 596static void ceph_x_reset(struct ceph_auth_client *ac) 597{ 598 struct ceph_x_info *xi = ac->private; 599 600 dout("reset\n"); 601 xi->starting = true; 602 xi->server_challenge = 0; 603} 604 605static void ceph_x_destroy(struct ceph_auth_client *ac) 606{ 607 struct ceph_x_info *xi = ac->private; 608 struct rb_node *p; 609 610 dout("ceph_x_destroy %p\n", ac); 611 ceph_crypto_key_destroy(&xi->secret); 612 613 while ((p = rb_first(&xi->ticket_handlers)) != NULL) { 614 struct ceph_x_ticket_handler *th = 615 rb_entry(p, struct ceph_x_ticket_handler, node); 616 remove_ticket_handler(ac, th); 617 } 618 619 if (xi->auth_authorizer.buf) 620 ceph_buffer_put(xi->auth_authorizer.buf); 621 622 kfree(ac->private); 623 ac->private = NULL; 624} 625 626static void ceph_x_invalidate_authorizer(struct ceph_auth_client *ac, 627 int peer_type) 628{ 629 struct ceph_x_ticket_handler *th; 630 631 th = get_ticket_handler(ac, peer_type); 632 if (!IS_ERR(th)) 633 remove_ticket_handler(ac, th); 634} 635 636 637static const struct ceph_auth_client_ops ceph_x_ops = { 638 .name = "x", 639 .is_authenticated = ceph_x_is_authenticated, 640 .should_authenticate = ceph_x_should_authenticate, 641 .build_request = ceph_x_build_request, 642 .handle_reply = ceph_x_handle_reply, 643 .create_authorizer = ceph_x_create_authorizer, 644 .verify_authorizer_reply = ceph_x_verify_authorizer_reply, 645 .destroy_authorizer = ceph_x_destroy_authorizer, 646 .invalidate_authorizer = ceph_x_invalidate_authorizer, 647 .reset = ceph_x_reset, 648 .destroy = ceph_x_destroy, 649}; 650 651 652int ceph_x_init(struct ceph_auth_client *ac) 653{ 654 struct ceph_x_info *xi; 655 int ret; 656 657 dout("ceph_x_init %p\n", ac); 658 ret = -ENOMEM; 659 xi = kzalloc(sizeof(*xi), GFP_NOFS); 660 if (!xi) 661 goto out; 662 663 ret = -EINVAL; 664 if (!ac->secret) { 665 pr_err("no secret set (for auth_x protocol)\n"); 666 goto out_nomem; 667 } 668 669 ret = ceph_crypto_key_unarmor(&xi->secret, ac->secret); 670 if (ret) 671 goto out_nomem; 672 673 xi->starting = true; 674 xi->ticket_handlers = RB_ROOT; 675 676 ac->protocol = CEPH_AUTH_CEPHX; 677 ac->private = xi; 678 ac->ops = &ceph_x_ops; 679 return 0; 680 681out_nomem: 682 kfree(xi); 683out: 684 return ret; 685} 686