1 /* 2 * Copyright 2004 Sun Microsystems, Inc. All rights reserved. 3 * Use is subject to license terms. 4 */ 5 6 #pragma ident "%Z%%M% %I% %E% SMI" 7 8 /* 9 * lib/gssapi/krb5/ser_sctx.c 10 * 11 * Copyright 1995 by the Massachusetts Institute of Technology. 12 * All Rights Reserved. 13 * 14 * Export of this software from the United States of America may 15 * require a specific license from the United States Government. 16 * It is the responsibility of any person or organization contemplating 17 * export to obtain such a license before exporting. 18 * 19 * WITHIN THAT CONSTRAINT, permission to use, copy, modify, and 20 * distribute this software and its documentation for any purpose and 21 * without fee is hereby granted, provided that the above copyright 22 * notice appear in all copies and that both that copyright notice and 23 * this permission notice appear in supporting documentation, and that 24 * the name of M.I.T. not be used in advertising or publicity pertaining 25 * to distribution of the software without specific, written prior 26 * permission. Furthermore if you modify this software you must label 27 * your software as modified software and not distribute it in such a 28 * fashion that it might be confused with the original M.I.T. software. 29 * M.I.T. makes no representations about the suitability of 30 * this software for any purpose. It is provided "as is" without express 31 * or implied warranty. 32 * 33 */ 34 35 /* 36 * ser_sctx.c - Handle [de]serialization of GSSAPI security context. 37 */ 38 39 /* Solaris Kerberos: order is important here. include gssapiP_krb5.h 40 * before all others, otherwise we get a LINT error from MALLOC macro 41 * being redefined in mechglueP.h */ 42 #include <gssapiP_krb5.h> 43 #include <k5-int.h> 44 45 /* 46 * This module contains routines to [de]serialize 47 * krb5_gss_enc_desc and krb5_gss_ctx_id_t. 48 * XXX This whole serialization abstraction is unnecessary in a 49 * non-messaging environment, which krb5 is. Someday, this should 50 * all get redone without the extra level of indirection. I've done 51 * some of this work here, since adding new serializers is an internal 52 * krb5 interface, and I won't use those. There is some more 53 * deobfuscation (no longer anonymizing pointers, mostly) which could 54 * still be done. --marc 55 */ 56 57 /*ARGSUSED*/ 58 static krb5_error_code 59 kg_oid_externalize(kcontext, arg, buffer, lenremain) 60 krb5_context kcontext; 61 krb5_pointer arg; 62 krb5_octet **buffer; 63 size_t *lenremain; 64 { 65 gss_OID oid = (gss_OID) arg; 66 krb5_error_code err; 67 68 err = krb5_ser_pack_int32(KV5M_GSS_OID, buffer, lenremain); 69 if (err) 70 return err; 71 err = krb5_ser_pack_int32((krb5_int32) oid->length, 72 buffer, lenremain); 73 if (err) 74 return err; 75 err = krb5_ser_pack_bytes((krb5_octet *) oid->elements, 76 oid->length, buffer, lenremain); 77 if (err) 78 return err; 79 err = krb5_ser_pack_int32(KV5M_GSS_OID, buffer, lenremain); 80 return err; 81 } 82 83 /*ARGSUSED*/ 84 static krb5_error_code 85 kg_oid_internalize(kcontext, argp, buffer, lenremain) 86 krb5_context kcontext; 87 krb5_pointer *argp; 88 krb5_octet **buffer; 89 size_t *lenremain; 90 { 91 /* Solaris Kerberos: note that by copying the argp pointer directly here, 92 * we avoid doing all the MALLOC and FREE calls later. 93 * Don't forget that when argp is ctx->mech_used, then this memory was 94 * already allocated. 95 */ 96 gss_OID oid = (gss_OID)argp; 97 krb5_int32 ibuf; 98 krb5_octet *bp; 99 size_t remain; 100 101 bp = *buffer; 102 remain = *lenremain; 103 104 /* Read in and check our magic number */ 105 if (krb5_ser_unpack_int32(&ibuf, &bp, &remain)) 106 return (EINVAL); 107 108 if (ibuf != KV5M_GSS_OID) 109 return (EINVAL); 110 /* oid = (gss_OID) MALLOC(sizeof(gss_OID_desc)); 111 if (oid == NULL) 112 return ENOMEM; 113 */ 114 115 if (krb5_ser_unpack_int32(&ibuf, &bp, &remain)) { 116 return EINVAL; 117 } 118 oid->length = ibuf; 119 oid->elements = MALLOC(ibuf); 120 if (oid->elements == NULL) { 121 oid->length = 0; 122 return (ENOMEM); 123 } 124 125 if (krb5_ser_unpack_bytes((krb5_octet *) oid->elements, 126 oid->length, &bp, &remain)) { 127 FREE(oid->elements, oid->length); 128 oid->length = 0; 129 return (EINVAL); 130 } 131 132 /* Read in and check our trailing magic number */ 133 if (krb5_ser_unpack_int32(&ibuf, &bp, &remain)) { 134 FREE (oid->elements, oid->length); 135 oid->length = 0; 136 return (EINVAL); 137 } 138 139 if (ibuf != KV5M_GSS_OID) { 140 FREE (oid->elements, oid->length); 141 oid->length = 0; 142 return (EINVAL); 143 } 144 145 *buffer = bp; 146 *lenremain = remain; 147 /* *argp = (krb5_pointer) oid; */ 148 return 0; 149 } 150 /*ARGSUSED*/ 151 krb5_error_code 152 kg_oid_size(kcontext, arg, sizep) 153 krb5_context kcontext; 154 krb5_pointer arg; 155 size_t *sizep; 156 { 157 krb5_error_code kret; 158 gss_OID oid; 159 size_t required; 160 161 kret = EINVAL; 162 oid = (gss_OID) arg; 163 if (oid) { 164 required = 2*sizeof(krb5_int32); /* For the header and trailer */ 165 required += sizeof(krb5_int32); 166 required += oid->length; 167 168 kret = 0; 169 170 *sizep += required; 171 } 172 173 return(kret); 174 } 175 176 /*ARGSUSED*/ 177 static krb5_error_code 178 kg_queue_externalize(kcontext, arg, buffer, lenremain) 179 krb5_context kcontext; 180 krb5_pointer arg; 181 krb5_octet **buffer; 182 size_t *lenremain; 183 { 184 krb5_error_code err; 185 err = krb5_ser_pack_int32(KV5M_GSS_QUEUE, buffer, lenremain); 186 if (err == 0) 187 err = g_queue_externalize(arg, buffer, lenremain); 188 if (err == 0) 189 err = krb5_ser_pack_int32(KV5M_GSS_QUEUE, buffer, lenremain); 190 return err; 191 } 192 193 /*ARGSUSED*/ 194 static krb5_error_code 195 kg_queue_internalize(kcontext, argp, buffer, lenremain) 196 krb5_context kcontext; 197 krb5_pointer *argp; 198 krb5_octet **buffer; 199 size_t *lenremain; 200 { 201 krb5_int32 ibuf; 202 krb5_octet *bp; 203 size_t remain; 204 krb5_error_code err; 205 206 bp = *buffer; 207 remain = *lenremain; 208 209 /* Read in and check our magic number */ 210 if (krb5_ser_unpack_int32(&ibuf, &bp, &remain)) 211 return (EINVAL); 212 213 if (ibuf != KV5M_GSS_QUEUE) 214 return (EINVAL); 215 216 err = g_queue_internalize(argp, &bp, &remain); 217 if (err) 218 return err; 219 220 /* Read in and check our trailing magic number */ 221 if (krb5_ser_unpack_int32(&ibuf, &bp, &remain)) 222 return (EINVAL); 223 224 if (ibuf != KV5M_GSS_QUEUE) 225 return (EINVAL); 226 227 *buffer = bp; 228 *lenremain = remain; 229 return 0; 230 } 231 /*ARGSUSED*/ 232 krb5_error_code 233 kg_queue_size(kcontext, arg, sizep) 234 krb5_context kcontext; 235 krb5_pointer arg; 236 size_t *sizep; 237 { 238 krb5_error_code kret; 239 size_t required; 240 241 kret = EINVAL; 242 if (arg) { 243 required = 2*sizeof(krb5_int32); /* For the header and trailer */ 244 (void) g_queue_size(arg, &required); 245 246 kret = 0; 247 *sizep += required; 248 } 249 return(kret); 250 } 251 252 /* 253 * Determine the size required for this krb5_gss_ctx_id_rec. 254 */ 255 krb5_error_code 256 kg_ctx_size(kcontext, arg, sizep) 257 krb5_context kcontext; 258 krb5_pointer arg; 259 size_t *sizep; 260 { 261 krb5_error_code kret; 262 krb5_gss_ctx_id_rec *ctx; 263 size_t required; 264 265 KRB5_LOG0(KRB5_INFO, "kg_ctx_size() start \n"); 266 267 /* 268 * krb5_gss_ctx_id_rec requires: 269 * krb5_int32 for KG_CONTEXT 270 * krb5_int32 for initiate. 271 * krb5_int32 for established. 272 * krb5_int32 for big_endian. 273 * krb5_int32 for have_acceptor_subkey. 274 * krb5_int32 for seed_init. 275 * krb5_int32 for gss_flags. 276 * sizeof(seed) for seed 277 * krb5_int32 for signalg. 278 * krb5_int32 for cksum_size. 279 * krb5_int32 for sealalg. 280 * krb5_int32 for endtime. 281 * krb5_int32 for flags. 282 * krb5_int64 for seq_send. 283 * krb5_int64 for seq_recv. 284 * ... for mech_used 285 * ... for here 286 * ... for there 287 * ... for subkey 288 * ... for enc 289 * ... for seq 290 * ... for seqstate 291 * ... for auth_context 292 * krb5_int32 for proto 293 * krb5_int32 for cksumtype 294 * ... for acceptor_subkey 295 * krb5_int32 for acceptor_key_cksumtype 296 * krb5_int32 for trailer. 297 */ 298 299 kret = EINVAL; 300 ctx = (krb5_gss_ctx_id_rec *) arg; 301 if (ctx) { 302 required = 16*sizeof(krb5_int32); 303 required += 2*sizeof(krb5_int64); 304 required += sizeof(ctx->seed); 305 306 kret = 0; 307 if (!kret && ctx->here) 308 kret = krb5_size_opaque(kcontext, 309 KV5M_PRINCIPAL, 310 (krb5_pointer) ctx->here, 311 &required); 312 313 if (!kret && ctx->there) 314 kret = krb5_size_opaque(kcontext, 315 KV5M_PRINCIPAL, 316 (krb5_pointer) ctx->there, 317 &required); 318 319 if (!kret && ctx->subkey) 320 kret = krb5_size_opaque(kcontext, 321 KV5M_KEYBLOCK, 322 (krb5_pointer) ctx->subkey, 323 &required); 324 325 if (!kret && ctx->enc) 326 kret = krb5_size_opaque(kcontext, 327 KV5M_KEYBLOCK, 328 (krb5_pointer) ctx->enc, 329 &required); 330 331 if (!kret && ctx->seq) 332 kret = krb5_size_opaque(kcontext, 333 KV5M_KEYBLOCK, 334 (krb5_pointer) ctx->seq, 335 &required); 336 337 if (!kret) 338 kret = kg_oid_size(kcontext, 339 (krb5_pointer) &ctx->mech_used, 340 &required); 341 342 if (!kret && ctx->seqstate) 343 kret = kg_queue_size(kcontext, ctx->seqstate, &required); 344 #ifndef PROVIDE_KERNEL_IMPORT 345 if (!kret) 346 kret = krb5_size_opaque(kcontext, 347 KV5M_AUTH_CONTEXT, 348 (krb5_pointer) ctx->auth_context, 349 &required); 350 #endif 351 if (!kret && ctx->acceptor_subkey) 352 kret = krb5_size_opaque(kcontext, 353 KV5M_KEYBLOCK, 354 (krb5_pointer) ctx->acceptor_subkey, 355 &required); 356 357 if (!kret) 358 *sizep += required; 359 } 360 KRB5_LOG1(KRB5_INFO, "kg_ctx_size() end, kret = %d required = %lu\n", kret, required); 361 return(kret); 362 } 363 364 /* 365 * Externalize this krb5_gss_ctx_id_ret. 366 */ 367 krb5_error_code 368 kg_ctx_externalize(kcontext, arg, buffer, lenremain) 369 krb5_context kcontext; 370 krb5_pointer arg; 371 krb5_octet **buffer; 372 size_t *lenremain; 373 { 374 krb5_error_code kret; 375 krb5_gss_ctx_id_rec *ctx; 376 size_t required; 377 krb5_octet *bp; 378 size_t remain; 379 /* SOLARIS KERBEROS: do not use accessor */ 380 381 KRB5_LOG0(KRB5_INFO, "kg_ctx_externalize() start\n"); 382 383 required = 0; 384 bp = *buffer; 385 remain = *lenremain; 386 kret = EINVAL; 387 ctx = (krb5_gss_ctx_id_rec *) arg; 388 if (ctx) { 389 kret = ENOMEM; 390 if (!kg_ctx_size(kcontext, arg, &required) && 391 (required <= remain)) { 392 /* Our identifier */ 393 (void) krb5_ser_pack_int32(KG_CONTEXT, &bp, &remain); 394 395 /* Now static data */ 396 (void) krb5_ser_pack_int32((krb5_int32) ctx->initiate, 397 &bp, &remain); 398 (void) krb5_ser_pack_int32((krb5_int32) ctx->established, 399 &bp, &remain); 400 (void) krb5_ser_pack_int32((krb5_int32) ctx->big_endian, 401 &bp, &remain); 402 (void) krb5_ser_pack_int32((krb5_int32) ctx->have_acceptor_subkey, 403 &bp, &remain); 404 (void) krb5_ser_pack_int32((krb5_int32) ctx->seed_init, 405 &bp, &remain); 406 (void) krb5_ser_pack_int32((krb5_int32) ctx->gss_flags, 407 &bp, &remain); 408 (void) krb5_ser_pack_bytes((krb5_octet *) ctx->seed, 409 sizeof(ctx->seed), 410 &bp, &remain); 411 (void) krb5_ser_pack_int32((krb5_int32) ctx->signalg, 412 &bp, &remain); 413 (void) krb5_ser_pack_int32((krb5_int32) ctx->cksum_size, 414 &bp, &remain); 415 (void) krb5_ser_pack_int32((krb5_int32) ctx->sealalg, 416 &bp, &remain); 417 (void) krb5_ser_pack_int32((krb5_int32) ctx->endtime, 418 &bp, &remain); 419 (void) krb5_ser_pack_int32((krb5_int32) ctx->krb_flags, 420 &bp, &remain); 421 (void) krb5_ser_pack_int64((krb5_int64) ctx->seq_send, 422 &bp, &remain); 423 (void) krb5_ser_pack_int64((krb5_int64) ctx->seq_recv, 424 &bp, &remain); 425 426 /* Now dynamic data */ 427 kret = 0; 428 429 if (!kret && &(ctx->mech_used)) 430 kret = kg_oid_externalize(kcontext, &(ctx->mech_used), 431 &bp, &remain); 432 433 if (!kret && ctx->here) 434 kret = krb5_externalize_opaque(kcontext, 435 KV5M_PRINCIPAL, 436 (krb5_pointer) ctx->here, 437 &bp, &remain); 438 439 if (!kret && ctx->there) 440 kret = krb5_externalize_opaque(kcontext, 441 KV5M_PRINCIPAL, 442 (krb5_pointer) ctx->there, 443 &bp, &remain); 444 445 if (!kret && ctx->subkey) 446 kret = krb5_externalize_opaque(kcontext, 447 KV5M_KEYBLOCK, 448 (krb5_pointer) ctx->subkey, 449 &bp, &remain); 450 451 if (!kret && ctx->enc) 452 kret = krb5_externalize_opaque(kcontext, 453 KV5M_KEYBLOCK, 454 (krb5_pointer) ctx->enc, 455 &bp, &remain); 456 457 if (!kret && ctx->seq) 458 kret = krb5_externalize_opaque(kcontext, 459 KV5M_KEYBLOCK, 460 (krb5_pointer) ctx->seq, 461 &bp, &remain); 462 463 if (!kret && ctx->seqstate) 464 kret = kg_queue_externalize(kcontext, 465 ctx->seqstate, &bp, &remain); 466 467 #ifndef PROVIDE_KERNEL_IMPORT 468 if (!kret) 469 kret = krb5_externalize_opaque(kcontext, 470 KV5M_AUTH_CONTEXT, 471 (krb5_pointer) ctx->auth_context, 472 &bp, &remain); 473 #endif 474 if (!kret) 475 kret = krb5_ser_pack_int32((krb5_int32) ctx->proto, 476 &bp, &remain); 477 if (!kret) 478 kret = krb5_ser_pack_int32((krb5_int32) ctx->cksumtype, 479 &bp, &remain); 480 if (!kret && ctx->acceptor_subkey) 481 kret = krb5_externalize_opaque(kcontext, 482 KV5M_KEYBLOCK, 483 (krb5_pointer) ctx->acceptor_subkey, 484 &bp, &remain); 485 if (!kret) 486 kret = krb5_ser_pack_int32((krb5_int32) ctx->acceptor_subkey_cksumtype, 487 &bp, &remain); 488 489 if (!kret) 490 (void) krb5_ser_pack_int32(KG_CONTEXT, &bp, &remain); 491 if (!kret) { 492 *buffer = bp; 493 *lenremain = remain; 494 } 495 } 496 } 497 KRB5_LOG(KRB5_INFO, "kg_ctx_externalize() end, kret = %d\n", kret); 498 return(kret); 499 } 500 501 /* 502 * Internalize this krb5_gss_ctx_id_t. 503 */ 504 krb5_error_code 505 kg_ctx_internalize(kcontext, argp, buffer, lenremain) 506 krb5_context kcontext; 507 krb5_pointer *argp; 508 krb5_octet **buffer; 509 size_t *lenremain; 510 { 511 krb5_error_code kret; 512 krb5_gss_ctx_id_rec *ctx; 513 krb5_int32 ibuf; 514 krb5_octet *bp; 515 size_t remain; 516 517 KRB5_LOG0(KRB5_INFO, "kg_ctx_internalize() start\n"); 518 519 bp = *buffer; 520 remain = *lenremain; 521 kret = EINVAL; 522 /* Read our magic number */ 523 if (krb5_ser_unpack_int32(&ibuf, &bp, &remain)) 524 ibuf = 0; 525 if (ibuf == KG_CONTEXT) { 526 kret = ENOMEM; 527 528 /* Get a context */ 529 if ((remain >= (16*sizeof(krb5_int32) 530 + 2*sizeof(krb5_int64) 531 + sizeof(ctx->seed))) && 532 (ctx = (krb5_gss_ctx_id_rec *) 533 xmalloc(sizeof(krb5_gss_ctx_id_rec)))) { 534 (void) memset(ctx, 0, sizeof(krb5_gss_ctx_id_rec)); 535 536 /* Get static data */ 537 (void) krb5_ser_unpack_int32(&ibuf, &bp, &remain); 538 ctx->initiate = (int) ibuf; 539 (void) krb5_ser_unpack_int32(&ibuf, &bp, &remain); 540 ctx->established = (int) ibuf; 541 (void) krb5_ser_unpack_int32(&ibuf, &bp, &remain); 542 ctx->big_endian = (int) ibuf; 543 (void) krb5_ser_unpack_int32(&ibuf, &bp, &remain); 544 ctx->have_acceptor_subkey = (int) ibuf; 545 (void) krb5_ser_unpack_int32(&ibuf, &bp, &remain); 546 ctx->seed_init = (int) ibuf; 547 (void) krb5_ser_unpack_int32(&ibuf, &bp, &remain); 548 ctx->gss_flags = (int) ibuf; 549 (void) krb5_ser_unpack_bytes((krb5_octet *) ctx->seed, 550 sizeof(ctx->seed), 551 &bp, &remain); 552 (void) krb5_ser_unpack_int32(&ibuf, &bp, &remain); 553 ctx->signalg = (int) ibuf; 554 (void) krb5_ser_unpack_int32(&ibuf, &bp, &remain); 555 ctx->cksum_size = (int) ibuf; 556 (void) krb5_ser_unpack_int32(&ibuf, &bp, &remain); 557 ctx->sealalg = (int) ibuf; 558 (void) krb5_ser_unpack_int32(&ibuf, &bp, &remain); 559 ctx->endtime = (krb5_timestamp) ibuf; 560 (void) krb5_ser_unpack_int32(&ibuf, &bp, &remain); 561 ctx->krb_flags = (krb5_flags) ibuf; 562 (void) krb5_ser_unpack_int64((krb5_int64 *) (&ctx->seq_send), &bp, &remain); 563 (void) krb5_ser_unpack_int64((krb5_int64 *) (&ctx->seq_recv), &bp, &remain); 564 if ((kret = kg_oid_internalize(kcontext, 565 (krb5_pointer)&ctx->mech_used, &bp, 566 &remain))) { 567 if (kret == EINVAL) 568 kret = 0; 569 } 570 /* Now get substructure data */ 571 if ((kret = krb5_internalize_opaque(kcontext, 572 KV5M_PRINCIPAL, 573 (krb5_pointer *) &ctx->here, 574 &bp, &remain))) { 575 if (kret == EINVAL) 576 kret = 0; 577 } 578 if (!kret && 579 (kret = krb5_internalize_opaque(kcontext, 580 KV5M_PRINCIPAL, 581 (krb5_pointer *) &ctx->there, 582 &bp, &remain))) { 583 if (kret == EINVAL) 584 kret = 0; 585 } 586 if (!kret && 587 (kret = krb5_internalize_opaque(kcontext, 588 KV5M_KEYBLOCK, 589 (krb5_pointer *) &ctx->subkey, 590 &bp, &remain))) { 591 if (kret == EINVAL) 592 kret = 0; 593 } 594 if (!kret && 595 (kret = krb5_internalize_opaque(kcontext, 596 KV5M_KEYBLOCK, 597 (krb5_pointer *) &ctx->enc, 598 &bp, &remain))) { 599 if (kret == EINVAL) 600 kret = 0; 601 } 602 if (!kret && 603 (kret = krb5_internalize_opaque(kcontext, 604 KV5M_KEYBLOCK, 605 (krb5_pointer *) &ctx->seq, 606 &bp, &remain))) { 607 if (kret == EINVAL) 608 kret = 0; 609 } 610 611 if (!kret) { 612 kret = kg_queue_internalize(kcontext, &ctx->seqstate, 613 &bp, &remain); 614 if (kret == EINVAL) 615 kret = 0; 616 } 617 #ifndef PROVIDE_KERNEL_IMPORT 618 if (!kret) 619 kret = krb5_internalize_opaque(kcontext, 620 KV5M_AUTH_CONTEXT, 621 (krb5_pointer *) &ctx->auth_context, 622 &bp, &remain); 623 #endif 624 if (!kret) 625 kret = krb5_ser_unpack_int32(&ibuf, &bp, &remain); 626 ctx->proto = ibuf; 627 if (!kret) 628 kret = krb5_ser_unpack_int32(&ibuf, &bp, &remain); 629 ctx->cksumtype = ibuf; 630 if (!kret && 631 (kret = krb5_internalize_opaque(kcontext, 632 KV5M_KEYBLOCK, 633 (krb5_pointer *) &ctx->acceptor_subkey, 634 &bp, &remain))) { 635 if (kret == EINVAL) 636 kret = 0; 637 } 638 if (!kret) 639 kret = krb5_ser_unpack_int32(&ibuf, &bp, &remain); 640 ctx->acceptor_subkey_cksumtype = ibuf; 641 done: 642 /* Get trailer */ 643 if (!kret) 644 kret = krb5_ser_unpack_int32(&ibuf, &bp, &remain); 645 646 if (!kret && ibuf != KG_CONTEXT) 647 kret = EINVAL; 648 649 if (!kret) { 650 *buffer = bp; 651 *lenremain = remain; 652 *argp = (krb5_pointer) ctx; 653 } else { 654 if (!kret && (ibuf != KG_CONTEXT)) 655 kret = EINVAL; 656 if (ctx->seq) 657 krb5_free_keyblock(kcontext, ctx->seq); 658 if (ctx->enc) 659 krb5_free_keyblock(kcontext, ctx->enc); 660 if (ctx->subkey) 661 krb5_free_keyblock(kcontext, ctx->subkey); 662 if (ctx->there) 663 krb5_free_principal(kcontext, ctx->there); 664 if (ctx->here) 665 krb5_free_principal(kcontext, ctx->here); 666 xfree_wrap(ctx, sizeof (krb5_gss_ctx_id_rec)); 667 } 668 } 669 } 670 671 KRB5_LOG(KRB5_INFO, "kg_ctx_internalize() end kret = %d\n", kret); 672 673 return(kret); 674 } 675