Merge remote-tracking branch 'origin/master'
[unleashed/lotheac.git] / usr / src / uts / common / gssapi / mechs / krb5 / mech / k5seal.c
blob746a2673174ca4df30ee0a4c8de92ef4467b0a36
1 /*
2 * Copyright (c) 1999, 2010, Oracle and/or its affiliates. All rights reserved.
3 */
4 /*
5 * Copyright 1993 by OpenVision Technologies, Inc.
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.
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.
27 * Copyright (C) 1998 by the FundsXpress, INC.
29 * All rights reserved.
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.
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.
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.
52 #include "gssapiP_krb5.h"
53 #include <k5-int.h>
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)
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;
90 /* Solaris Kerberos: check for recognized signalg and sealalg */
91 KRB5_LOG0(KRB5_INFO, "make_seal_token_v1() start\n");
92 #ifdef _KERNEL
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.
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);
104 if ((code = init_key_kef(context->kef_cipher_mt, enc))) {
105 return (code);
107 #endif /* _KERNEL */
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;
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);
126 tmsglen = msglen;
127 } else {
128 tmsglen = 0;
129 msglen = text->length;
130 pad = 0;
132 tlen = g_token_size((gss_OID) oid, 14+cksum_size+tmsglen);
134 if ((t = (unsigned char *) xmalloc(tlen)) == NULL)
135 return(ENOMEM);
137 /*** fill in the token */
139 ptr = t;
140 g_make_token_header((gss_OID) oid, 14+cksum_size+tmsglen, &ptr, toktype);
142 /* 0..1 SIGN_ALG */
143 ptr[0] = (unsigned char) (signalg & 0xff);
144 ptr[1] = (unsigned char) ((signalg >> 8) & 0xff);
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;
156 /* 4..5 Filler */
157 ptr[4] = 0xff;
158 ptr[5] = 0xff;
160 /* pad the plaintext, encrypt if needed, and stick it in the token */
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 */
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);
192 md5cksum.length = sumlen;
195 if ((plain = (unsigned char *) xmalloc(msglen ? msglen : 1)) == NULL) {
196 xfree_wrap(t, tlen);
197 return(ENOMEM);
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);
210 (void) memcpy(plain+conflen, text->value, text->length);
211 if (pad) (void) memset(plain+conflen+text->length, pad, pad);
213 /* compute the checksum */
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);
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));
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);
240 switch(signalg) {
241 case SGN_ALG_DES_MAC_MD5:
242 case 3:
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);
251 KRB5_LOG(KRB5_ERR, "make_seal_token_v1() end, kg_encrypt() "
252 "error code=%d\n", code);
253 return code;
256 cksum.length = cksum_size;
257 cksum.contents = md5cksum.contents + 16 - cksum.length;
259 (void) memcpy(ptr+14, cksum.contents, cksum.length);
260 break;
262 case SGN_ALG_HMAC_SHA1_DES3_KD:
264 * Using key derivation, the call to krb5_c_make_checksum
265 * already dealt with encrypting.
267 if (md5cksum.length != cksum_size)
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
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;
289 xfree_wrap(md5cksum.contents, md5cksum.length);
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);
297 KRB5_LOG(KRB5_ERR, "make_seal_token_v1() end, kg_make_seq_num() "
298 "error code=%d\n", code);
299 return(code);
302 if (encrypt) {
303 switch(sealalg) {
304 case SEAL_ALG_MICROSOFT_RC4:
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)
316 xfree_wrap(plain, msglen ? msglen : 1);
317 xfree_wrap(t, tlen);
318 return(code);
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)
329 xfree_wrap(plain, msglen ? msglen : 1);
330 xfree_wrap(t, tlen);
331 return(code);
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);
345 }else {
346 if (tmsglen)
347 (void) memcpy(ptr+14+cksum_size, plain, tmsglen);
349 xfree_wrap(plain, msglen ? msglen : 1);
352 /* that's it. return the token */
354 (*seqnum)++;
355 *seqnum &= (ulong_t)0xffffffffU;
357 token->length = tlen;
358 token->value = (void *) t;
360 KRB5_LOG0(KRB5_INFO, "make_seal_token_v1() end\n");
361 return(0);
364 /* if signonly is true, ignore conf_req, conf_state,
365 and do not encode the ENC_TYPE, MSG_LENGTH, or MSG_TEXT fields */
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;
379 krb5_gss_ctx_id_rec *ctx;
380 krb5_error_code code;
381 krb5_timestamp now;
382 krb5_context context;
384 KRB5_LOG0(KRB5_INFO, "kg_seal() start");
386 output_message_buffer->length = 0;
387 output_message_buffer->value = NULL;
389 /* Only default qop or matching established cryptosystem is allowed.
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);
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);
409 ctx = (krb5_gss_ctx_id_rec *) context_handle;
411 if (ctx->subkey == NULL && !ctx->established) {
412 *minor_status = KG_CTX_INCOMPLETE;
413 return(GSS_S_NO_CONTEXT);
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);
424 switch (ctx->proto)
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;
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);
453 if (conf_state)
454 *conf_state = conf_req_flag;
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);
464 KRB5_LOG0(KRB5_INFO, "kg_seal() end\n");
465 return (GSS_S_COMPLETE);