1 /* 2 * CDDL HEADER START 3 * 4 * The contents of this file are subject to the terms of the 5 * Common Development and Distribution License, Version 1.0 only 6 * (the "License"). You may not use this file except in compliance 7 * with the License. 8 * 9 * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE 10 * or http://www.opensolaris.org/os/licensing. 11 * See the License for the specific language governing permissions 12 * and limitations under the License. 13 * 14 * When distributing Covered Code, include this CDDL HEADER in each 15 * file and include the License file at usr/src/OPENSOLARIS.LICENSE. 16 * If applicable, add the following below this CDDL HEADER, with the 17 * fields enclosed by brackets "[]" replaced with your own identifying 18 * information: Portions Copyright [yyyy] [name of copyright owner] 19 * 20 * CDDL HEADER END 21 */ 22 /* 23 * Copyright 2004 Sun Microsystems, Inc. All rights reserved. 24 * Use is subject to license terms. 25 */ 26 27 #pragma ident "%Z%%M% %I% %E% SMI" 28 29 /* 30 * A module that implements a dummy security mechanism. 31 * It's mainly used to test GSS-API application. Multiple tokens 32 * exchanged during security context establishment can be 33 * specified through dummy_mech.conf located in /etc. 34 */ 35 36 char _depends_on[] = "misc/kgssapi"; 37 38 #include <sys/types.h> 39 #include <sys/modctl.h> 40 #include <sys/errno.h> 41 #include <gssapiP_dummy.h> 42 #include <gssapi_err_generic.h> 43 #include <mechglueP.h> 44 #include <gssapi/kgssapi_defs.h> 45 #include <sys/debug.h> 46 47 #ifdef DUMMY_MECH_DEBUG 48 /* 49 * Kernel kgssd module debugging aid. The global variable "dummy_mech_log" 50 * is a bit mask which allows various types of debugging messages 51 * to be printed out. 52 * 53 * dummy_mech_log & 1 will cause actual failures to be printed. 54 * dummy_mech_log & 2 will cause informational messages to be 55 * printed on the client side of kgssd. 56 * dummy_mech_log & 4 will cause informational messages to be 57 * printed on the server side of kgssd. 58 * dummy_mech_log & 8 will cause informational messages to be 59 * printed on both client and server side of kgssd. 60 */ 61 62 uint_t dummy_mech_log = 1; 63 #endif 64 65 /* Local defines */ 66 #define MAGIC_TOKEN_NUMBER 12345 67 /* private routines for dummy_mechanism */ 68 static gss_buffer_desc make_dummy_token_msg(void *data, int datalen); 69 70 static int der_length_size(int); 71 72 static void der_write_length(unsigned char **, int); 73 static int der_read_length(unsigned char **, int *); 74 static int g_token_size(gss_OID mech, unsigned int body_size); 75 static void g_make_token_header(gss_OID mech, int body_size, 76 unsigned char **buf, int tok_type); 77 static int g_verify_token_header(gss_OID mech, int *body_size, 78 unsigned char **buf_in, int tok_type, 79 int toksize); 80 81 /* private global variables */ 82 static int dummy_token_nums; 83 84 /* 85 * This OID: 86 * { iso(1) org(3) internet(6) dod(1) private(4) enterprises(1) sun(42) 87 * products(2) gssapi(26) mechtypes(1) dummy(2) } 88 */ 89 90 static struct gss_config dummy_mechanism = 91 {{10, "\053\006\001\004\001\052\002\032\001\002"}, 92 NULL, /* context */ 93 NULL, /* next */ 94 TRUE, /* uses_kmod */ 95 /* EXPORT DELETE START */ /* CRYPT DELETE START */ 96 dummy_gss_unseal, 97 /* EXPORT DELETE END */ /* CRYPT DELETE END */ 98 dummy_gss_delete_sec_context, 99 /* EXPORT DELETE START */ /* CRYPT DELETE START */ 100 dummy_gss_seal, 101 /* EXPORT DELETE END */ /* CRYPT DELETE END */ 102 dummy_gss_import_sec_context, 103 /* EXPORT DELETE START */ 104 /* CRYPT DELETE START */ 105 #if 0 106 /* CRYPT DELETE END */ 107 dummy_gss_seal, 108 dummy_gss_unseal, 109 /* CRYPT DELETE START */ 110 #endif 111 /* CRYPT DELETE END */ 112 /* EXPORT DELETE END */ 113 dummy_gss_sign, 114 dummy_gss_verify 115 }; 116 117 static gss_mechanism 118 gss_mech_initialize() 119 { 120 dprintf("Entering gss_mech_initialize\n"); 121 122 if (dummy_token_nums == 0) 123 dummy_token_nums = 1; 124 125 dprintf("Leaving gss_mech_initialize\n"); 126 return (&dummy_mechanism); 127 } 128 129 /* 130 * Clean up after a failed mod_install() 131 */ 132 static void 133 gss_mech_fini() 134 { 135 /* Nothing to do */ 136 } 137 138 139 /* 140 * Module linkage information for the kernel. 141 */ 142 extern struct mod_ops mod_miscops; 143 144 static struct modlmisc modlmisc = { 145 &mod_miscops, "in-kernel dummy GSS mechanism" 146 }; 147 148 static struct modlinkage modlinkage = { 149 MODREV_1, 150 (void *)&modlmisc, 151 NULL 152 }; 153 154 static int dummy_fini_code = EBUSY; 155 156 int 157 _init() 158 { 159 int retval; 160 gss_mechanism mech, tmp; 161 162 mech = gss_mech_initialize(); 163 164 mutex_enter(&__kgss_mech_lock); 165 tmp = __kgss_get_mechanism(&mech->mech_type); 166 if (tmp != NULL) { 167 DUMMY_MECH_LOG0(8, 168 "dummy GSS mechanism: mechanism already in table.\n"); 169 if (tmp->uses_kmod == TRUE) { 170 DUMMY_MECH_LOG0(8, "dummy GSS mechanism: mechanism " 171 "table supports kernel operations!\n"); 172 } 173 /* 174 * keep us loaded, but let us be unloadable. This 175 * will give the developer time to trouble shoot 176 */ 177 dummy_fini_code = 0; 178 } else { 179 __kgss_add_mechanism(mech); 180 ASSERT(__kgss_get_mechanism(&mech->mech_type) == mech); 181 } 182 mutex_exit(&__kgss_mech_lock); 183 184 if ((retval = mod_install(&modlinkage)) != 0) 185 gss_mech_fini(); /* clean up */ 186 187 return (retval); 188 } 189 190 int 191 _fini() 192 { 193 int ret = dummy_fini_code; 194 195 if (ret == 0) { 196 ret = (mod_remove(&modlinkage)); 197 } 198 return (ret); 199 } 200 201 int 202 _info(struct modinfo *modinfop) 203 { 204 return (mod_info(&modlinkage, modinfop)); 205 } 206 207 208 /*ARGSUSED*/ 209 static OM_uint32 210 dummy_gss_sign(context, minor_status, context_handle, 211 qop_req, message_buffer, message_token, 212 gssd_ctx_verifier) 213 void *context; 214 OM_uint32 *minor_status; 215 gss_ctx_id_t context_handle; 216 int qop_req; 217 gss_buffer_t message_buffer; 218 gss_buffer_t message_token; 219 OM_uint32 gssd_ctx_verifier; 220 { 221 dummy_gss_ctx_id_rec *ctx; 222 char token_string[] = "dummy_gss_sign"; 223 224 dprintf("Entering gss_sign\n"); 225 226 if (context_handle == GSS_C_NO_CONTEXT) 227 return (GSS_S_NO_CONTEXT); 228 ctx = (dummy_gss_ctx_id_rec *) context_handle; 229 ASSERT(ctx->established == 1); 230 ASSERT(ctx->token_number == MAGIC_TOKEN_NUMBER); 231 232 *message_token = make_dummy_token_msg( 233 token_string, strlen(token_string)); 234 235 dprintf("Leaving gss_sign\n"); 236 return (GSS_S_COMPLETE); 237 } 238 239 /*ARGSUSED*/ 240 static OM_uint32 241 dummy_gss_verify(context, minor_status, context_handle, 242 message_buffer, token_buffer, qop_state, 243 gssd_ctx_verifier) 244 void *context; 245 OM_uint32 *minor_status; 246 gss_ctx_id_t context_handle; 247 gss_buffer_t message_buffer; 248 gss_buffer_t token_buffer; 249 int *qop_state; 250 OM_uint32 gssd_ctx_verifier; 251 { 252 unsigned char *ptr; 253 int bodysize; 254 int err; 255 dummy_gss_ctx_id_rec *ctx; 256 257 dprintf("Entering gss_verify\n"); 258 259 if (context_handle == GSS_C_NO_CONTEXT) 260 return (GSS_S_NO_CONTEXT); 261 262 ctx = (dummy_gss_ctx_id_rec *) context_handle; 263 ASSERT(ctx->established == 1); 264 ASSERT(ctx->token_number == MAGIC_TOKEN_NUMBER); 265 /* Check for defective input token. */ 266 267 ptr = (unsigned char *) token_buffer->value; 268 if (err = g_verify_token_header((gss_OID)gss_mech_dummy, &bodysize, 269 &ptr, 0, 270 token_buffer->length)) { 271 *minor_status = err; 272 return (GSS_S_DEFECTIVE_TOKEN); 273 } 274 275 *qop_state = GSS_C_QOP_DEFAULT; 276 277 dprintf("Leaving gss_verify\n"); 278 return (GSS_S_COMPLETE); 279 } 280 281 /* EXPORT DELETE START */ 282 /*ARGSUSED*/ 283 static OM_uint32 284 dummy_gss_seal(context, minor_status, context_handle, conf_req_flag, 285 qop_req, input_message_buffer, conf_state, 286 output_message_buffer, gssd_ctx_verifier) 287 void *context; 288 OM_uint32 *minor_status; 289 gss_ctx_id_t context_handle; 290 int conf_req_flag; 291 int qop_req; 292 gss_buffer_t input_message_buffer; 293 int *conf_state; 294 gss_buffer_t output_message_buffer; 295 OM_uint32 gssd_ctx_verifier; 296 { 297 gss_buffer_desc output; 298 dummy_gss_ctx_id_rec *ctx; 299 dprintf("Entering gss_seal\n"); 300 301 if (context_handle == GSS_C_NO_CONTEXT) 302 return (GSS_S_NO_CONTEXT); 303 ctx = (dummy_gss_ctx_id_rec *) context_handle; 304 ASSERT(ctx->established == 1); 305 ASSERT(ctx->token_number == MAGIC_TOKEN_NUMBER); 306 /* Copy the input message to output message */ 307 output = make_dummy_token_msg( 308 input_message_buffer->value, input_message_buffer->length); 309 310 if (conf_state) 311 *conf_state = 1; 312 313 *output_message_buffer = output; 314 315 dprintf("Leaving gss_seal\n"); 316 return (GSS_S_COMPLETE); 317 } 318 319 /*ARGSUSED*/ 320 static OM_uint32 321 dummy_gss_unseal(context, minor_status, context_handle, 322 input_message_buffer, output_message_buffer, 323 conf_state, qop_state, gssd_ctx_verifier) 324 void *context; 325 OM_uint32 *minor_status; 326 gss_ctx_id_t context_handle; 327 gss_buffer_t input_message_buffer; 328 gss_buffer_t output_message_buffer; 329 int *conf_state; 330 int *qop_state; 331 OM_uint32 gssd_ctx_verifier; 332 { 333 gss_buffer_desc output; 334 dummy_gss_ctx_id_rec *ctx; 335 unsigned char *ptr; 336 int bodysize; 337 int err; 338 339 dprintf("Entering gss_unseal\n"); 340 341 if (context_handle == GSS_C_NO_CONTEXT) 342 return (GSS_S_NO_CONTEXT); 343 344 ctx = (dummy_gss_ctx_id_rec *) context_handle; 345 ASSERT(ctx->established == 1); 346 ASSERT(ctx->token_number == MAGIC_TOKEN_NUMBER); 347 348 ptr = (unsigned char *) input_message_buffer->value; 349 if (err = g_verify_token_header((gss_OID)gss_mech_dummy, &bodysize, 350 &ptr, 0, 351 input_message_buffer->length)) { 352 *minor_status = err; 353 return (GSS_S_DEFECTIVE_TOKEN); 354 } 355 output.length = bodysize; 356 output.value = (void *)MALLOC(output.length); 357 (void) memcpy(output.value, ptr, output.length); 358 359 *output_message_buffer = output; 360 *qop_state = GSS_C_QOP_DEFAULT; 361 362 if (conf_state) 363 *conf_state = 1; 364 365 dprintf("Leaving gss_unseal\n"); 366 return (GSS_S_COMPLETE); 367 } 368 369 /* EXPORT DELETE END */ 370 371 /*ARGSUSED*/ 372 OM_uint32 373 dummy_gss_import_sec_context(ct, minor_status, interprocess_token, 374 context_handle) 375 void *ct; 376 OM_uint32 *minor_status; 377 gss_buffer_t interprocess_token; 378 gss_ctx_id_t *context_handle; 379 { 380 unsigned char *ptr; 381 int bodysize; 382 int err; 383 384 /* Assume that we got ctx from the interprocess token. */ 385 dummy_gss_ctx_id_t ctx; 386 387 dprintf("Entering import_sec_context\n"); 388 ptr = (unsigned char *) interprocess_token->value; 389 if (err = g_verify_token_header((gss_OID)gss_mech_dummy, &bodysize, 390 &ptr, 0, 391 interprocess_token->length)) { 392 *minor_status = err; 393 return (GSS_S_DEFECTIVE_TOKEN); 394 } 395 ctx = (dummy_gss_ctx_id_t)MALLOC(sizeof (dummy_gss_ctx_id_rec)); 396 ctx->token_number = MAGIC_TOKEN_NUMBER; 397 ctx->established = 1; 398 399 *context_handle = (gss_ctx_id_t)ctx; 400 401 dprintf("Leaving import_sec_context\n"); 402 return (GSS_S_COMPLETE); 403 } 404 405 /*ARGSUSED*/ 406 static OM_uint32 407 dummy_gss_delete_sec_context(ct, minor_status, 408 context_handle, output_token, 409 gssd_ctx_verifier) 410 void *ct; 411 OM_uint32 *minor_status; 412 gss_ctx_id_t *context_handle; 413 gss_buffer_t output_token; 414 OM_uint32 gssd_ctx_verifier; 415 { 416 dummy_gss_ctx_id_t ctx; 417 418 dprintf("Entering delete_sec_context\n"); 419 420 /* Make the length to 0, so the output token is not sent to peer */ 421 if (output_token) { 422 output_token->length = 0; 423 output_token->value = NULL; 424 } 425 426 if (*context_handle == GSS_C_NO_CONTEXT) { 427 *minor_status = 0; 428 return (GSS_S_COMPLETE); 429 } 430 431 ctx = (dummy_gss_ctx_id_rec *) *context_handle; 432 ASSERT(ctx->established == 1); 433 ASSERT(ctx->token_number == MAGIC_TOKEN_NUMBER); 434 435 FREE(ctx, sizeof (dummy_gss_ctx_id_rec)); 436 *context_handle = GSS_C_NO_CONTEXT; 437 438 dprintf("Leaving delete_sec_context\n"); 439 return (GSS_S_COMPLETE); 440 } 441 442 static int 443 der_length_size(int length) 444 { 445 if (length < (1<<7)) 446 return (1); 447 else if (length < (1<<8)) 448 return (2); 449 else if (length < (1<<16)) 450 return (3); 451 else if (length < (1<<24)) 452 return (4); 453 else 454 return (5); 455 } 456 457 static void 458 der_write_length(unsigned char ** buf, int length) 459 { 460 if (length < (1<<7)) { 461 *(*buf)++ = (unsigned char) length; 462 } else { 463 *(*buf)++ = (unsigned char) (der_length_size(length)+127); 464 if (length >= (1<<24)) 465 *(*buf)++ = (unsigned char) (length>>24); 466 if (length >= (1<<16)) 467 *(*buf)++ = (unsigned char) ((length>>16)&0xff); 468 if (length >= (1<<8)) 469 *(*buf)++ = (unsigned char) ((length>>8)&0xff); 470 *(*buf)++ = (unsigned char) (length&0xff); 471 } 472 } 473 474 static int 475 der_read_length(buf, bufsize) 476 unsigned char **buf; 477 int *bufsize; 478 { 479 unsigned char sf; 480 int ret; 481 482 if (*bufsize < 1) 483 return (-1); 484 sf = *(*buf)++; 485 (*bufsize)--; 486 if (sf & 0x80) { 487 if ((sf &= 0x7f) > ((*bufsize)-1)) 488 return (-1); 489 if (sf > DUMMY_SIZE_OF_INT) 490 return (-1); 491 ret = 0; 492 for (; sf; sf--) { 493 ret = (ret<<8) + (*(*buf)++); 494 (*bufsize)--; 495 } 496 } else { 497 ret = sf; 498 } 499 500 return (ret); 501 } 502 503 static int 504 g_token_size(mech, body_size) 505 gss_OID mech; 506 unsigned int body_size; 507 { 508 /* set body_size to sequence contents size */ 509 body_size += 4 + (int)mech->length; /* NEED overflow check */ 510 return (1 + der_length_size(body_size) + body_size); 511 } 512 513 static void 514 g_make_token_header(mech, body_size, buf, tok_type) 515 gss_OID mech; 516 int body_size; 517 unsigned char **buf; 518 int tok_type; 519 { 520 *(*buf)++ = 0x60; 521 der_write_length(buf, 4 + mech->length + body_size); 522 *(*buf)++ = 0x06; 523 *(*buf)++ = (unsigned char) mech->length; 524 TWRITE_STR(*buf, mech->elements, ((int)mech->length)); 525 *(*buf)++ = (unsigned char) ((tok_type>>8)&0xff); 526 *(*buf)++ = (unsigned char) (tok_type&0xff); 527 } 528 529 static int 530 g_verify_token_header(mech, body_size, buf_in, tok_type, toksize) 531 gss_OID mech; 532 int *body_size; 533 unsigned char **buf_in; 534 int tok_type; 535 int toksize; 536 { 537 unsigned char *buf = *buf_in; 538 int seqsize; 539 gss_OID_desc toid; 540 int ret = 0; 541 542 if ((toksize -= 1) < 0) 543 return (G_BAD_TOK_HEADER); 544 if (*buf++ != 0x60) 545 return (G_BAD_TOK_HEADER); 546 547 if ((seqsize = der_read_length(&buf, &toksize)) < 0) 548 return (G_BAD_TOK_HEADER); 549 550 if (seqsize != toksize) 551 return (G_BAD_TOK_HEADER); 552 553 if ((toksize -= 1) < 0) 554 return (G_BAD_TOK_HEADER); 555 if (*buf++ != 0x06) 556 return (G_BAD_TOK_HEADER); 557 558 if ((toksize -= 1) < 0) 559 return (G_BAD_TOK_HEADER); 560 toid.length = *buf++; 561 562 if ((toksize -= toid.length) < 0) 563 return (G_BAD_TOK_HEADER); 564 toid.elements = buf; 565 buf += toid.length; 566 567 if (! g_OID_equal(&toid, mech)) 568 ret = G_WRONG_MECH; 569 570 /* 571 * G_WRONG_MECH is not returned immediately because it's more important 572 * to return G_BAD_TOK_HEADER if the token header is in fact bad 573 */ 574 575 if ((toksize -= 2) < 0) 576 return (G_BAD_TOK_HEADER); 577 578 if ((*buf++ != ((tok_type>>8)&0xff)) || 579 (*buf++ != (tok_type&0xff))) 580 return (G_BAD_TOK_HEADER); 581 582 if (!ret) { 583 *buf_in = buf; 584 *body_size = toksize; 585 } 586 587 return (ret); 588 } 589 590 static gss_buffer_desc 591 make_dummy_token_msg(void *data, int dataLen) 592 { 593 gss_buffer_desc buffer; 594 int tlen; 595 unsigned char *t; 596 unsigned char *ptr; 597 598 if (data == NULL) { 599 buffer.length = 0; 600 buffer.value = NULL; 601 return (buffer); 602 } 603 604 tlen = g_token_size((gss_OID)gss_mech_dummy, dataLen); 605 t = (unsigned char *) MALLOC(tlen); 606 ptr = t; 607 608 g_make_token_header((gss_OID)gss_mech_dummy, dataLen, &ptr, 0); 609 (void) memcpy(ptr, data, dataLen); 610 611 buffer.length = tlen; 612 buffer.value = (void *) t; 613 return (buffer); 614 } 615