1 /* 2 * Copyright 2006 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 * Copyright 1993 by OpenVision Technologies, Inc. 10 * 11 * Permission to use, copy, modify, distribute, and sell this software 12 * and its documentation for any purpose is hereby granted without fee, 13 * provided that the above copyright notice appears in all copies and 14 * that both that copyright notice and this permission notice appear in 15 * supporting documentation, and that the name of OpenVision not be used 16 * in advertising or publicity pertaining to distribution of the software 17 * without specific, written prior permission. OpenVision makes no 18 * representations about the suitability of this software for any 19 * purpose. It is provided "as is" without express or implied warranty. 20 * 21 * OPENVISION DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, 22 * INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO 23 * EVENT SHALL OPENVISION BE LIABLE FOR ANY SPECIAL, INDIRECT OR 24 * CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF 25 * USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR 26 * OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR 27 * PERFORMANCE OF THIS SOFTWARE. 28 */ 29 30 /* 31 * Copyright (C) 1998 by the FundsXpress, INC. 32 * 33 * All rights reserved. 34 * 35 * Export of this software from the United States of America may require 36 * a specific license from the United States Government. It is the 37 * responsibility of any person or organization contemplating export to 38 * obtain such a license before exporting. 39 * 40 * WITHIN THAT CONSTRAINT, permission to use, copy, modify, and 41 * distribute this software and its documentation for any purpose and 42 * without fee is hereby granted, provided that the above copyright 43 * notice appear in all copies and that both that copyright notice and 44 * this permission notice appear in supporting documentation, and that 45 * the name of FundsXpress. not be used in advertising or publicity pertaining 46 * to distribution of the software without specific, written prior 47 * permission. FundsXpress makes no representations about the suitability of 48 * this software for any purpose. It is provided "as is" without express 49 * or implied warranty. 50 * 51 * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR 52 * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED 53 * WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE. 54 */ 55 56 #include <gssapiP_krb5.h> 57 #include <k5-int.h> 58 59 static krb5_error_code 60 make_seal_token_v1 PROTOTYPE((krb5_context context, 61 krb5_keyblock *enc, 62 krb5_keyblock *seq, 63 gssint_uint64 *seqnum, 64 int direction, 65 gss_buffer_t text, 66 gss_buffer_t token, 67 int signalg, 68 int cksum_size, 69 int sealalg, 70 int encrypt, 71 int toktype, 72 int bigend, 73 gss_OID oid)); 74 75 static krb5_error_code 76 make_seal_token_v1(context, enc, seq, seqnum, direction, text, token, 77 signalg, cksum_size, sealalg, encrypt, toktype, 78 bigend, oid) 79 krb5_context context; 80 krb5_keyblock *enc; 81 krb5_keyblock *seq; 82 gssint_uint64 *seqnum; 83 int direction; 84 gss_buffer_t text; 85 gss_buffer_t token; 86 int signalg; 87 int cksum_size; 88 int sealalg; 89 int encrypt; 90 int toktype; 91 int bigend; 92 gss_OID oid; 93 { 94 krb5_error_code code; 95 size_t sumlen; 96 char *data_ptr; 97 krb5_data plaind; 98 krb5_checksum md5cksum; 99 krb5_checksum cksum; 100 /* 101 * msglen contains the message length 102 * we are signing/encrypting. tmsglen 103 * contains the length of the message 104 * we plan to write out to the token. 105 * tlen is the length of the token 106 * including header. 107 */ 108 int conflen=0, tmsglen, tlen, msglen; 109 unsigned char *t, *ptr; 110 unsigned char *plain; 111 unsigned char pad; 112 krb5_keyusage sign_usage = KG_USAGE_SIGN; 113 OM_uint32 seqnum32; 114 115 /* Solaris Kerberos: check for recognized signalg and sealalg */ 116 KRB5_LOG0(KRB5_INFO, "make_seal_token_v1() start\n"); 117 #ifdef _KERNEL 118 /* 119 * Because the ARCFOUR code bypasses the standard 120 * crypto interfaces, we must make sure the kernel 121 * crypto framework mechanism types are properly 122 * initialized here. 123 */ 124 context->kef_cipher_mt = get_cipher_mech_type(context, seq); 125 context->kef_hash_mt = get_hash_mech_type(context, seq); 126 if ((code = init_key_kef(context->kef_cipher_mt, seq))) { 127 return (code); 128 } 129 if ((code = init_key_kef(context->kef_cipher_mt, enc))) { 130 return (code); 131 } 132 #endif /* _KERNEL */ 133 134 /* create the token buffer */ 135 /* Do we need confounder? */ 136 if (encrypt || (!bigend && (toktype == KG_TOK_SEAL_MSG))) 137 conflen = kg_confounder_size(context, enc); 138 else 139 conflen = 0; 140 141 if (toktype == KG_TOK_SEAL_MSG) { 142 switch (sealalg) { 143 case SEAL_ALG_MICROSOFT_RC4: 144 msglen = conflen + text->length+1; 145 pad = 1; 146 break; 147 default: 148 /* XXX knows that des block size is 8 */ 149 msglen = (conflen+text->length+8)&(~7); 150 pad = 8-(text->length%8); 151 } 152 tmsglen = msglen; 153 } else { 154 tmsglen = 0; 155 msglen = text->length; 156 pad = 0; 157 } 158 159 tlen = g_token_size((gss_OID) oid, 14+cksum_size+tmsglen); 160 161 if ((t = (unsigned char *) xmalloc(tlen)) == NULL) 162 return(ENOMEM); 163 164 /*** fill in the token */ 165 166 ptr = t; 167 168 g_make_token_header((gss_OID) oid, 14+cksum_size+tmsglen, &ptr, toktype); 169 170 /* 0..1 SIGN_ALG */ 171 172 ptr[0] = (unsigned char) (signalg & 0xff); 173 ptr[1] = (unsigned char) ((signalg >> 8) & 0xff); 174 175 /* 2..3 SEAL_ALG or Filler */ 176 177 if ((toktype == KG_TOK_SEAL_MSG) && encrypt) { 178 ptr[2] = (unsigned char) (sealalg & 0xff); 179 ptr[3] = (unsigned char) ((sealalg >> 8) & 0xff); 180 } else { 181 /* No seal */ 182 ptr[2] = 0xff; 183 ptr[3] = 0xff; 184 } 185 186 /* 4..5 Filler */ 187 188 ptr[4] = 0xff; 189 ptr[5] = 0xff; 190 191 /* pad the plaintext, encrypt if needed, and stick it in the token */ 192 193 /* initialize the the cksum */ 194 switch (signalg) { 195 case SGN_ALG_DES_MAC_MD5: 196 case SGN_ALG_MD2_5: 197 md5cksum.checksum_type = CKSUMTYPE_RSA_MD5; 198 break; 199 case SGN_ALG_HMAC_SHA1_DES3_KD: 200 md5cksum.checksum_type = CKSUMTYPE_HMAC_SHA1_DES3; 201 break; 202 case SGN_ALG_HMAC_MD5: 203 md5cksum.checksum_type = CKSUMTYPE_HMAC_MD5_ARCFOUR; 204 if (toktype != KG_TOK_SEAL_MSG) 205 sign_usage = 15; 206 break; 207 default: 208 KRB5_LOG(KRB5_ERR, "make_seal_token_v1() end, error2 signalg=%d\n", 209 signalg); 210 #ifndef _KERNEL 211 abort (); 212 #else 213 return (GSS_S_DEFECTIVE_TOKEN); 214 #endif /* _KERNEL */ 215 } 216 217 code = krb5_c_checksum_length(context, md5cksum.checksum_type, &sumlen); 218 if (code) { 219 KRB5_LOG(KRB5_ERR, "make_seal_token_v1() end, krb5_c_checksum_length() " 220 "error code=%d\n", code); 221 return(code); 222 } 223 md5cksum.length = (size_t)sumlen; 224 225 if ((plain = (unsigned char *) xmalloc(msglen ? msglen : 1)) == NULL) { 226 xfree_wrap(t, tlen); 227 return(ENOMEM); 228 } 229 230 if (conflen) { 231 if ((code = kg_make_confounder(context, enc, plain))) { 232 xfree_wrap(plain, msglen ? msglen : 1); 233 xfree_wrap(t, tlen); 234 KRB5_LOG(KRB5_ERR, "make_seal_token_v1() end, " 235 "kg_make_confounder() error code=%d\n", code); 236 return(code); 237 } 238 } 239 240 (void) memcpy(plain+conflen, text->value, text->length); 241 if (pad) 242 (void) memset(plain+conflen+text->length, pad, pad); 243 244 /* compute the checksum */ 245 246 /* 8 = head of token body as specified by mech spec */ 247 if (! (data_ptr = (char *) xmalloc(8 + 248 (bigend ? text->length : msglen)))) { 249 xfree_wrap(plain, msglen ? msglen : 1); 250 xfree_wrap(t, tlen); 251 return(ENOMEM); 252 } 253 (void) memcpy(data_ptr, ptr-2, 8); 254 if (bigend) 255 (void) memcpy(data_ptr+8, text->value, text->length); 256 else 257 (void) memcpy(data_ptr+8, plain, msglen); 258 259 plaind.length = 8 + (bigend ? text->length : msglen); 260 plaind.data = data_ptr; 261 262 code = krb5_c_make_checksum(context, md5cksum.checksum_type, seq, 263 sign_usage, &plaind, &md5cksum); 264 265 xfree_wrap(data_ptr,8 + (bigend ? text->length : msglen)); 266 267 if (code) { 268 KRB5_LOG(KRB5_ERR, "make_seal_token_v1() end, " 269 "krb5_c_make_checksum() error code=%d\n", code); 270 xfree_wrap(plain, msglen ? msglen : 1); 271 xfree_wrap(t, tlen); 272 return(code); 273 } 274 275 switch(signalg) { 276 case SGN_ALG_DES_MAC_MD5: 277 case 3: 278 279 if ((code = kg_encrypt(context, seq, KG_USAGE_SEAL, 280 (g_OID_equal(oid, gss_mech_krb5_old) ? 281 seq->contents : NULL), 282 md5cksum.contents, md5cksum.contents, 16))) { 283 xfree_wrap(md5cksum.contents, md5cksum.length); 284 xfree_wrap(t, tlen); 285 286 KRB5_LOG(KRB5_ERR, "make_seal_token_v1() end, kg_encrypt() " 287 "error code=%d\n", code); 288 return code; 289 } 290 291 cksum.length = cksum_size; 292 cksum.contents = md5cksum.contents + 16 - cksum.length; 293 294 (void) memcpy(ptr+14, cksum.contents, cksum.length); 295 break; 296 297 case SGN_ALG_HMAC_SHA1_DES3_KD: 298 /* 299 * Using key derivation, the call to krb5_c_make_checksum 300 * already dealt with encrypting. 301 */ 302 if (md5cksum.length != cksum_size) 303 { 304 KRB5_LOG1(KRB5_ERR, "make_seal_token_v1() end, error " 305 "md5cksum.length %d != " 306 "cksum_size %d\n", 307 md5cksum.length, cksum_size); 308 #ifndef _KERNEL 309 abort (); 310 #else 311 return (GSS_S_DEFECTIVE_TOKEN); 312 #endif 313 } 314 (void) memcpy(ptr+14, md5cksum.contents, md5cksum.length); 315 break; 316 case SGN_ALG_HMAC_MD5: 317 KRB5_LOG(KRB5_INFO, "make_seal_token_v1() cksum_size = %d", 318 cksum_size); 319 (void) memcpy(ptr+14, md5cksum.contents, cksum_size); 320 break; 321 } 322 323 xfree_wrap(md5cksum.contents, md5cksum.length); 324 325 /* create the seq_num */ 326 seqnum32 = (OM_uint32)(*seqnum & 0xFFFFFFFF); 327 if ((code = kg_make_seq_num(context, seq, direction?0:0xff, seqnum32, 328 ptr+14, ptr+6))) { 329 xfree_wrap(t, tlen); 330 331 KRB5_LOG(KRB5_ERR, "make_seal_token_v1() end, kg_make_seq_num() " 332 "error code=%d\n", code); 333 return(code); 334 } 335 if (encrypt) { 336 switch(sealalg) { 337 case SEAL_ALG_MICROSOFT_RC4: 338 { 339 unsigned char bigend_seqnum[4]; 340 krb5_keyblock *enc_key; 341 int i; 342 bigend_seqnum[0] = (*seqnum>>24) & 0xff; 343 bigend_seqnum[1] = (*seqnum>>16) & 0xff; 344 bigend_seqnum[2] = (*seqnum>>8) & 0xff; 345 bigend_seqnum[3] = *seqnum & 0xff; 346 code = krb5_copy_keyblock (context, enc, &enc_key); 347 if (code) 348 { 349 xfree_wrap(plain, msglen ? msglen : 1); 350 xfree_wrap(t, tlen); 351 return(code); 352 } 353 for (i = 0; i <= 15; i++) 354 ((char *) enc_key->contents)[i] ^=0xf0; 355 code = kg_arcfour_docrypt (context, 356 enc_key, 0, 357 bigend_seqnum, 4, 358 plain, tmsglen, 359 ptr+14+cksum_size); 360 krb5_free_keyblock (context, enc_key); 361 if (code) 362 { 363 xfree_wrap(plain, msglen ? msglen : 1); 364 xfree_wrap(t, tlen); 365 return(code); 366 } 367 } 368 break; 369 default: 370 if ((code = kg_encrypt(context, enc, KG_USAGE_SEAL, NULL, 371 (krb5_pointer) plain, 372 (krb5_pointer) (ptr+cksum_size+14), 373 tmsglen))) { 374 xfree_wrap(plain, msglen ? msglen : 1); 375 xfree_wrap(t, tlen); 376 return(code); 377 } 378 } 379 }else { 380 if (tmsglen) 381 (void) memcpy(ptr+14+cksum_size, plain, tmsglen); 382 } 383 xfree_wrap(plain, msglen ? msglen : 1); 384 385 /* that's it. return the token */ 386 387 (*seqnum)++; 388 *seqnum &= (ulong_t)0xffffffffU; 389 390 token->length = tlen; 391 token->value = (void *) t; 392 393 KRB5_LOG0(KRB5_INFO, "make_seal_token_v1() end\n"); 394 return(0); 395 } 396 397 /* if signonly is true, ignore conf_req, conf_state, 398 and do not encode the ENC_TYPE, MSG_LENGTH, or MSG_TEXT fields */ 399 400 OM_uint32 401 kg_seal(context, minor_status, context_handle, conf_req_flag, qop_req, 402 input_message_buffer, conf_state, output_message_buffer, toktype) 403 krb5_context context; 404 OM_uint32 *minor_status; 405 gss_ctx_id_t context_handle; 406 int conf_req_flag; 407 int qop_req; 408 gss_buffer_t input_message_buffer; 409 int *conf_state; 410 gss_buffer_t output_message_buffer; 411 int toktype; 412 { 413 krb5_gss_ctx_id_rec *ctx; 414 krb5_error_code code; 415 krb5_timestamp now; 416 417 KRB5_LOG0(KRB5_INFO, "kg_seal() start"); 418 419 output_message_buffer->length = 0; 420 output_message_buffer->value = NULL; 421 422 /* Only default qop or matching established cryptosystem is allowed. 423 424 There are NO EXTENSIONS to this set for AES and friends! The 425 new spec says "just use 0". The old spec plus extensions would 426 actually allow for certain non-zero values. Fix this to handle 427 them later. */ 428 if (qop_req != 0) { 429 *minor_status = (OM_uint32) G_UNKNOWN_QOP; 430 KRB5_LOG0(KRB5_ERR, "kg_seal() end, error G_UNKNOWN_QOP\n"); 431 return (GSS_S_BAD_QOP); 432 } 433 434 /* validate the context handle */ 435 if (! kg_validate_ctx_id(context_handle)) { 436 *minor_status = (OM_uint32) G_VALIDATE_FAILED; 437 KRB5_LOG0(KRB5_ERR, "kg_seal() kg_validate_ctx_id() end, " 438 "error GSS_S_NO_CONTEXT\n"); 439 return (GSS_S_NO_CONTEXT); 440 } 441 442 ctx = (krb5_gss_ctx_id_rec *) context_handle; 443 444 if (ctx->subkey == NULL && !ctx->established) { 445 *minor_status = KG_CTX_INCOMPLETE; 446 return(GSS_S_NO_CONTEXT); 447 } 448 449 if ((code = krb5_timeofday(context, &now))) { 450 *minor_status = code; 451 KRB5_LOG(KRB5_ERR, "kg_seal() end, krb5_timeofday() error code=%d\n", code); 452 return (GSS_S_FAILURE); 453 } 454 455 switch (ctx->proto) 456 { 457 case 0: 458 code = make_seal_token_v1(context, ctx->enc, ctx->seq, 459 &ctx->seq_send, ctx->initiate, 460 input_message_buffer, output_message_buffer, 461 ctx->signalg, ctx->cksum_size, ctx->sealalg, 462 conf_req_flag, toktype, ctx->big_endian, 463 &ctx->mech_used); 464 break; 465 case 1: 466 code = gss_krb5int_make_seal_token_v3(context, ctx, 467 input_message_buffer, 468 output_message_buffer, 469 conf_req_flag, toktype); 470 break; 471 default: 472 code = G_UNKNOWN_QOP; 473 break; 474 } 475 476 if (code) { 477 *minor_status = code; 478 KRB5_LOG(KRB5_ERR, "kg_seal() end, make_seal_token_v1() " 479 "error code=%d\n", code); 480 return (GSS_S_FAILURE); 481 } 482 483 if (conf_state) 484 *conf_state = conf_req_flag; 485 486 *minor_status = 0; 487 if (ctx->endtime < now) { 488 (void) gss_release_buffer(minor_status, output_message_buffer); 489 KRB5_LOG(KRB5_ERR, "kg_seal() end, error GSS_S_CONTEXT_EXPIRED " 490 "ctx->endtime = %d\n", ctx->endtime); 491 return (GSS_S_CONTEXT_EXPIRED); 492 } 493 494 KRB5_LOG0(KRB5_INFO, "kg_seal() end\n"); 495 return (GSS_S_COMPLETE); 496 } 497