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