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