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
55static krb5_error_code
56make_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
367OM_uint32
368kg_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