1178825Sdfr/*
2233294Sstas * Copyright (c) 1997 - 2003 Kungliga Tekniska H��gskolan
3233294Sstas * (Royal Institute of Technology, Stockholm, Sweden).
4233294Sstas * All rights reserved.
5178825Sdfr *
6233294Sstas * Redistribution and use in source and binary forms, with or without
7233294Sstas * modification, are permitted provided that the following conditions
8233294Sstas * are met:
9178825Sdfr *
10233294Sstas * 1. Redistributions of source code must retain the above copyright
11233294Sstas *    notice, this list of conditions and the following disclaimer.
12178825Sdfr *
13233294Sstas * 2. Redistributions in binary form must reproduce the above copyright
14233294Sstas *    notice, this list of conditions and the following disclaimer in the
15233294Sstas *    documentation and/or other materials provided with the distribution.
16178825Sdfr *
17233294Sstas * 3. Neither the name of the Institute nor the names of its contributors
18233294Sstas *    may be used to endorse or promote products derived from this software
19233294Sstas *    without specific prior written permission.
20178825Sdfr *
21233294Sstas * THIS SOFTWARE IS PROVIDED BY THE INSTITUTE AND CONTRIBUTORS ``AS IS'' AND
22233294Sstas * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
23233294Sstas * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
24233294Sstas * ARE DISCLAIMED.  IN NO EVENT SHALL THE INSTITUTE OR CONTRIBUTORS BE LIABLE
25233294Sstas * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
26233294Sstas * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
27233294Sstas * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
28233294Sstas * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
29233294Sstas * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
30233294Sstas * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
31233294Sstas * SUCH DAMAGE.
32178825Sdfr */
33178825Sdfr
34233294Sstas#include "gsskrb5_locl.h"
35178825Sdfr
36178825Sdfr/*
37178825Sdfr * Return initiator subkey, or if that doesn't exists, the subkey.
38178825Sdfr */
39178825Sdfr
40178825Sdfrkrb5_error_code
41178825Sdfr_gsskrb5i_get_initiator_subkey(const gsskrb5_ctx ctx,
42178825Sdfr			       krb5_context context,
43178825Sdfr			       krb5_keyblock **key)
44178825Sdfr{
45178825Sdfr    krb5_error_code ret;
46178825Sdfr    *key = NULL;
47178825Sdfr
48178825Sdfr    if (ctx->more_flags & LOCAL) {
49178825Sdfr	ret = krb5_auth_con_getlocalsubkey(context,
50233294Sstas				     ctx->auth_context,
51178825Sdfr				     key);
52178825Sdfr    } else {
53178825Sdfr	ret = krb5_auth_con_getremotesubkey(context,
54233294Sstas				      ctx->auth_context,
55178825Sdfr				      key);
56178825Sdfr    }
57178825Sdfr    if (ret == 0 && *key == NULL)
58178825Sdfr	ret = krb5_auth_con_getkey(context,
59233294Sstas				   ctx->auth_context,
60178825Sdfr				   key);
61178825Sdfr    if (ret == 0 && *key == NULL) {
62233294Sstas	krb5_set_error_message(context, 0, "No initiator subkey available");
63178825Sdfr	return GSS_KRB5_S_KG_NO_SUBKEY;
64178825Sdfr    }
65178825Sdfr    return ret;
66178825Sdfr}
67178825Sdfr
68178825Sdfrkrb5_error_code
69178825Sdfr_gsskrb5i_get_acceptor_subkey(const gsskrb5_ctx ctx,
70178825Sdfr			      krb5_context context,
71178825Sdfr			      krb5_keyblock **key)
72178825Sdfr{
73178825Sdfr    krb5_error_code ret;
74178825Sdfr    *key = NULL;
75178825Sdfr
76178825Sdfr    if (ctx->more_flags & LOCAL) {
77178825Sdfr	ret = krb5_auth_con_getremotesubkey(context,
78233294Sstas				      ctx->auth_context,
79178825Sdfr				      key);
80178825Sdfr    } else {
81178825Sdfr	ret = krb5_auth_con_getlocalsubkey(context,
82233294Sstas				     ctx->auth_context,
83178825Sdfr				     key);
84178825Sdfr    }
85178825Sdfr    if (ret == 0 && *key == NULL) {
86233294Sstas	krb5_set_error_message(context, 0, "No acceptor subkey available");
87178825Sdfr	return GSS_KRB5_S_KG_NO_SUBKEY;
88178825Sdfr    }
89178825Sdfr    return ret;
90178825Sdfr}
91178825Sdfr
92178825SdfrOM_uint32
93178825Sdfr_gsskrb5i_get_token_key(const gsskrb5_ctx ctx,
94178825Sdfr			krb5_context context,
95178825Sdfr			krb5_keyblock **key)
96178825Sdfr{
97178825Sdfr    _gsskrb5i_get_acceptor_subkey(ctx, context, key);
98178825Sdfr    if(*key == NULL) {
99178825Sdfr	/*
100178825Sdfr	 * Only use the initiator subkey or ticket session key if an
101178825Sdfr	 * acceptor subkey was not required.
102178825Sdfr	 */
103178825Sdfr	if ((ctx->more_flags & ACCEPTOR_SUBKEY) == 0)
104178825Sdfr	    _gsskrb5i_get_initiator_subkey(ctx, context, key);
105178825Sdfr    }
106178825Sdfr    if (*key == NULL) {
107233294Sstas	krb5_set_error_message(context, 0, "No token key available");
108178825Sdfr	return GSS_KRB5_S_KG_NO_SUBKEY;
109178825Sdfr    }
110178825Sdfr    return 0;
111178825Sdfr}
112178825Sdfr
113178825Sdfrstatic OM_uint32
114178825Sdfrsub_wrap_size (
115178825Sdfr            OM_uint32 req_output_size,
116178825Sdfr            OM_uint32 * max_input_size,
117178825Sdfr	    int blocksize,
118178825Sdfr	    int extrasize
119178825Sdfr           )
120178825Sdfr{
121233294Sstas    size_t len, total_len;
122178825Sdfr
123178825Sdfr    len = 8 + req_output_size + blocksize + extrasize;
124178825Sdfr
125178825Sdfr    _gsskrb5_encap_length(len, &len, &total_len, GSS_KRB5_MECHANISM);
126178825Sdfr
127178825Sdfr    total_len -= req_output_size; /* token length */
128178825Sdfr    if (total_len < req_output_size) {
129178825Sdfr        *max_input_size = (req_output_size - total_len);
130178825Sdfr        (*max_input_size) &= (~(OM_uint32)(blocksize - 1));
131178825Sdfr    } else {
132178825Sdfr        *max_input_size = 0;
133178825Sdfr    }
134178825Sdfr    return GSS_S_COMPLETE;
135178825Sdfr}
136178825Sdfr
137233294SstasOM_uint32 GSSAPI_CALLCONV
138178825Sdfr_gsskrb5_wrap_size_limit (
139178825Sdfr            OM_uint32 * minor_status,
140178825Sdfr            const gss_ctx_id_t context_handle,
141178825Sdfr            int conf_req_flag,
142178825Sdfr            gss_qop_t qop_req,
143178825Sdfr            OM_uint32 req_output_size,
144178825Sdfr            OM_uint32 * max_input_size
145178825Sdfr           )
146178825Sdfr{
147178825Sdfr  krb5_context context;
148178825Sdfr  krb5_keyblock *key;
149178825Sdfr  OM_uint32 ret;
150178825Sdfr  krb5_keytype keytype;
151178825Sdfr  const gsskrb5_ctx ctx = (const gsskrb5_ctx) context_handle;
152178825Sdfr
153178825Sdfr  GSSAPI_KRB5_INIT (&context);
154178825Sdfr
155233294Sstas  if (ctx->more_flags & IS_CFX)
156233294Sstas      return _gssapi_wrap_size_cfx(minor_status, ctx, context,
157233294Sstas				   conf_req_flag, qop_req,
158233294Sstas				   req_output_size, max_input_size);
159233294Sstas
160178825Sdfr  HEIMDAL_MUTEX_lock(&ctx->ctx_id_mutex);
161178825Sdfr  ret = _gsskrb5i_get_token_key(ctx, context, &key);
162178825Sdfr  HEIMDAL_MUTEX_unlock(&ctx->ctx_id_mutex);
163178825Sdfr  if (ret) {
164178825Sdfr      *minor_status = ret;
165178825Sdfr      return GSS_S_FAILURE;
166178825Sdfr  }
167178825Sdfr  krb5_enctype_to_keytype (context, key->keytype, &keytype);
168178825Sdfr
169178825Sdfr  switch (keytype) {
170178825Sdfr  case KEYTYPE_DES :
171233294Sstas#ifdef HEIM_WEAK_CRYPTO
172178825Sdfr      ret = sub_wrap_size(req_output_size, max_input_size, 8, 22);
173233294Sstas#else
174233294Sstas      ret = GSS_S_FAILURE;
175233294Sstas#endif
176178825Sdfr      break;
177233294Sstas  case ENCTYPE_ARCFOUR_HMAC_MD5:
178233294Sstas  case ENCTYPE_ARCFOUR_HMAC_MD5_56:
179178825Sdfr      ret = _gssapi_wrap_size_arcfour(minor_status, ctx, context,
180233294Sstas				      conf_req_flag, qop_req,
181178825Sdfr				      req_output_size, max_input_size, key);
182178825Sdfr      break;
183178825Sdfr  case KEYTYPE_DES3 :
184178825Sdfr      ret = sub_wrap_size(req_output_size, max_input_size, 8, 34);
185178825Sdfr      break;
186178825Sdfr  default :
187233294Sstas      abort();
188178825Sdfr      break;
189178825Sdfr  }
190178825Sdfr  krb5_free_keyblock (context, key);
191178825Sdfr  *minor_status = 0;
192178825Sdfr  return ret;
193178825Sdfr}
194178825Sdfr
195233294Sstas#ifdef HEIM_WEAK_CRYPTO
196233294Sstas
197178825Sdfrstatic OM_uint32
198178825Sdfrwrap_des
199178825Sdfr           (OM_uint32 * minor_status,
200178825Sdfr            const gsskrb5_ctx ctx,
201178825Sdfr	    krb5_context context,
202178825Sdfr            int conf_req_flag,
203178825Sdfr            gss_qop_t qop_req,
204178825Sdfr            const gss_buffer_t input_message_buffer,
205178825Sdfr            int * conf_state,
206178825Sdfr            gss_buffer_t output_message_buffer,
207178825Sdfr	    krb5_keyblock *key
208178825Sdfr           )
209178825Sdfr{
210178825Sdfr  u_char *p;
211233294Sstas  EVP_MD_CTX *md5;
212178825Sdfr  u_char hash[16];
213178825Sdfr  DES_key_schedule schedule;
214233294Sstas  EVP_CIPHER_CTX des_ctx;
215178825Sdfr  DES_cblock deskey;
216178825Sdfr  DES_cblock zero;
217233294Sstas  size_t i;
218178825Sdfr  int32_t seq_number;
219178825Sdfr  size_t len, total_len, padlength, datalen;
220178825Sdfr
221233294Sstas  if (IS_DCE_STYLE(ctx)) {
222233294Sstas    padlength = 0;
223233294Sstas    datalen = input_message_buffer->length;
224233294Sstas    len = 22 + 8;
225233294Sstas    _gsskrb5_encap_length (len, &len, &total_len, GSS_KRB5_MECHANISM);
226233294Sstas    total_len += datalen;
227233294Sstas    datalen += 8;
228233294Sstas  } else {
229233294Sstas    padlength = 8 - (input_message_buffer->length % 8);
230233294Sstas    datalen = input_message_buffer->length + padlength + 8;
231233294Sstas    len = datalen + 22;
232233294Sstas    _gsskrb5_encap_length (len, &len, &total_len, GSS_KRB5_MECHANISM);
233233294Sstas  }
234178825Sdfr
235178825Sdfr  output_message_buffer->length = total_len;
236178825Sdfr  output_message_buffer->value  = malloc (total_len);
237178825Sdfr  if (output_message_buffer->value == NULL) {
238178825Sdfr    output_message_buffer->length = 0;
239178825Sdfr    *minor_status = ENOMEM;
240178825Sdfr    return GSS_S_FAILURE;
241178825Sdfr  }
242178825Sdfr
243178825Sdfr  p = _gsskrb5_make_header(output_message_buffer->value,
244178825Sdfr			      len,
245178825Sdfr			      "\x02\x01", /* TOK_ID */
246178825Sdfr			      GSS_KRB5_MECHANISM);
247178825Sdfr
248178825Sdfr  /* SGN_ALG */
249178825Sdfr  memcpy (p, "\x00\x00", 2);
250178825Sdfr  p += 2;
251178825Sdfr  /* SEAL_ALG */
252178825Sdfr  if(conf_req_flag)
253178825Sdfr      memcpy (p, "\x00\x00", 2);
254178825Sdfr  else
255178825Sdfr      memcpy (p, "\xff\xff", 2);
256178825Sdfr  p += 2;
257178825Sdfr  /* Filler */
258178825Sdfr  memcpy (p, "\xff\xff", 2);
259178825Sdfr  p += 2;
260178825Sdfr
261178825Sdfr  /* fill in later */
262178825Sdfr  memset (p, 0, 16);
263178825Sdfr  p += 16;
264178825Sdfr
265178825Sdfr  /* confounder + data + pad */
266178825Sdfr  krb5_generate_random_block(p, 8);
267178825Sdfr  memcpy (p + 8, input_message_buffer->value,
268178825Sdfr	  input_message_buffer->length);
269178825Sdfr  memset (p + 8 + input_message_buffer->length, padlength, padlength);
270178825Sdfr
271178825Sdfr  /* checksum */
272233294Sstas  md5 = EVP_MD_CTX_create();
273233294Sstas  EVP_DigestInit_ex(md5, EVP_md5(), NULL);
274233294Sstas  EVP_DigestUpdate(md5, p - 24, 8);
275233294Sstas  EVP_DigestUpdate(md5, p, datalen);
276233294Sstas  EVP_DigestFinal_ex(md5, hash, NULL);
277233294Sstas  EVP_MD_CTX_destroy(md5);
278178825Sdfr
279178825Sdfr  memset (&zero, 0, sizeof(zero));
280178825Sdfr  memcpy (&deskey, key->keyvalue.data, sizeof(deskey));
281233294Sstas  DES_set_key_unchecked (&deskey, &schedule);
282178825Sdfr  DES_cbc_cksum ((void *)hash, (void *)hash, sizeof(hash),
283178825Sdfr		 &schedule, &zero);
284178825Sdfr  memcpy (p - 8, hash, 8);
285178825Sdfr
286178825Sdfr  /* sequence number */
287178825Sdfr  HEIMDAL_MUTEX_lock(&ctx->ctx_id_mutex);
288178825Sdfr  krb5_auth_con_getlocalseqnumber (context,
289178825Sdfr				   ctx->auth_context,
290178825Sdfr				   &seq_number);
291178825Sdfr
292178825Sdfr  p -= 16;
293178825Sdfr  p[0] = (seq_number >> 0)  & 0xFF;
294178825Sdfr  p[1] = (seq_number >> 8)  & 0xFF;
295178825Sdfr  p[2] = (seq_number >> 16) & 0xFF;
296178825Sdfr  p[3] = (seq_number >> 24) & 0xFF;
297178825Sdfr  memset (p + 4,
298178825Sdfr	  (ctx->more_flags & LOCAL) ? 0 : 0xFF,
299178825Sdfr	  4);
300178825Sdfr
301233294Sstas  EVP_CIPHER_CTX_init(&des_ctx);
302233294Sstas  EVP_CipherInit_ex(&des_ctx, EVP_des_cbc(), NULL, key->keyvalue.data, p + 8, 1);
303233294Sstas  EVP_Cipher(&des_ctx, p, p, 8);
304233294Sstas  EVP_CIPHER_CTX_cleanup(&des_ctx);
305178825Sdfr
306178825Sdfr  krb5_auth_con_setlocalseqnumber (context,
307178825Sdfr			       ctx->auth_context,
308178825Sdfr			       ++seq_number);
309178825Sdfr  HEIMDAL_MUTEX_unlock(&ctx->ctx_id_mutex);
310178825Sdfr
311178825Sdfr  /* encrypt the data */
312178825Sdfr  p += 16;
313178825Sdfr
314178825Sdfr  if(conf_req_flag) {
315178825Sdfr      memcpy (&deskey, key->keyvalue.data, sizeof(deskey));
316178825Sdfr
317178825Sdfr      for (i = 0; i < sizeof(deskey); ++i)
318178825Sdfr	  deskey[i] ^= 0xf0;
319233294Sstas
320233294Sstas      EVP_CIPHER_CTX_init(&des_ctx);
321233294Sstas      EVP_CipherInit_ex(&des_ctx, EVP_des_cbc(), NULL, deskey, zero, 1);
322233294Sstas      EVP_Cipher(&des_ctx, p, p, datalen);
323233294Sstas      EVP_CIPHER_CTX_cleanup(&des_ctx);
324178825Sdfr  }
325178825Sdfr  memset (deskey, 0, sizeof(deskey));
326178825Sdfr  memset (&schedule, 0, sizeof(schedule));
327178825Sdfr
328178825Sdfr  if(conf_state != NULL)
329178825Sdfr      *conf_state = conf_req_flag;
330178825Sdfr  *minor_status = 0;
331178825Sdfr  return GSS_S_COMPLETE;
332178825Sdfr}
333178825Sdfr
334233294Sstas#endif
335233294Sstas
336178825Sdfrstatic OM_uint32
337178825Sdfrwrap_des3
338178825Sdfr           (OM_uint32 * minor_status,
339178825Sdfr            const gsskrb5_ctx ctx,
340178825Sdfr	    krb5_context context,
341178825Sdfr            int conf_req_flag,
342178825Sdfr            gss_qop_t qop_req,
343178825Sdfr            const gss_buffer_t input_message_buffer,
344178825Sdfr            int * conf_state,
345178825Sdfr            gss_buffer_t output_message_buffer,
346178825Sdfr	    krb5_keyblock *key
347178825Sdfr           )
348178825Sdfr{
349178825Sdfr  u_char *p;
350178825Sdfr  u_char seq[8];
351178825Sdfr  int32_t seq_number;
352178825Sdfr  size_t len, total_len, padlength, datalen;
353178825Sdfr  uint32_t ret;
354178825Sdfr  krb5_crypto crypto;
355178825Sdfr  Checksum cksum;
356178825Sdfr  krb5_data encdata;
357178825Sdfr
358233294Sstas  if (IS_DCE_STYLE(ctx)) {
359233294Sstas    padlength = 0;
360233294Sstas    datalen = input_message_buffer->length;
361233294Sstas    len = 34 + 8;
362233294Sstas    _gsskrb5_encap_length (len, &len, &total_len, GSS_KRB5_MECHANISM);
363233294Sstas    total_len += datalen;
364233294Sstas    datalen += 8;
365233294Sstas  } else {
366233294Sstas    padlength = 8 - (input_message_buffer->length % 8);
367233294Sstas    datalen = input_message_buffer->length + padlength + 8;
368233294Sstas    len = datalen + 34;
369233294Sstas    _gsskrb5_encap_length (len, &len, &total_len, GSS_KRB5_MECHANISM);
370233294Sstas  }
371178825Sdfr
372178825Sdfr  output_message_buffer->length = total_len;
373178825Sdfr  output_message_buffer->value  = malloc (total_len);
374178825Sdfr  if (output_message_buffer->value == NULL) {
375178825Sdfr    output_message_buffer->length = 0;
376178825Sdfr    *minor_status = ENOMEM;
377178825Sdfr    return GSS_S_FAILURE;
378178825Sdfr  }
379178825Sdfr
380178825Sdfr  p = _gsskrb5_make_header(output_message_buffer->value,
381178825Sdfr			      len,
382178825Sdfr			      "\x02\x01", /* TOK_ID */
383233294Sstas			      GSS_KRB5_MECHANISM);
384178825Sdfr
385178825Sdfr  /* SGN_ALG */
386178825Sdfr  memcpy (p, "\x04\x00", 2);	/* HMAC SHA1 DES3-KD */
387178825Sdfr  p += 2;
388178825Sdfr  /* SEAL_ALG */
389178825Sdfr  if(conf_req_flag)
390178825Sdfr      memcpy (p, "\x02\x00", 2); /* DES3-KD */
391178825Sdfr  else
392178825Sdfr      memcpy (p, "\xff\xff", 2);
393178825Sdfr  p += 2;
394178825Sdfr  /* Filler */
395178825Sdfr  memcpy (p, "\xff\xff", 2);
396178825Sdfr  p += 2;
397178825Sdfr
398178825Sdfr  /* calculate checksum (the above + confounder + data + pad) */
399178825Sdfr
400178825Sdfr  memcpy (p + 20, p - 8, 8);
401178825Sdfr  krb5_generate_random_block(p + 28, 8);
402178825Sdfr  memcpy (p + 28 + 8, input_message_buffer->value,
403178825Sdfr	  input_message_buffer->length);
404178825Sdfr  memset (p + 28 + 8 + input_message_buffer->length, padlength, padlength);
405178825Sdfr
406178825Sdfr  ret = krb5_crypto_init(context, key, 0, &crypto);
407178825Sdfr  if (ret) {
408178825Sdfr      free (output_message_buffer->value);
409178825Sdfr      output_message_buffer->length = 0;
410178825Sdfr      output_message_buffer->value = NULL;
411178825Sdfr      *minor_status = ret;
412178825Sdfr      return GSS_S_FAILURE;
413178825Sdfr  }
414178825Sdfr
415178825Sdfr  ret = krb5_create_checksum (context,
416178825Sdfr			      crypto,
417178825Sdfr			      KRB5_KU_USAGE_SIGN,
418178825Sdfr			      0,
419178825Sdfr			      p + 20,
420178825Sdfr			      datalen + 8,
421178825Sdfr			      &cksum);
422178825Sdfr  krb5_crypto_destroy (context, crypto);
423178825Sdfr  if (ret) {
424178825Sdfr      free (output_message_buffer->value);
425178825Sdfr      output_message_buffer->length = 0;
426178825Sdfr      output_message_buffer->value = NULL;
427178825Sdfr      *minor_status = ret;
428178825Sdfr      return GSS_S_FAILURE;
429178825Sdfr  }
430178825Sdfr
431178825Sdfr  /* zero out SND_SEQ + SGN_CKSUM in case */
432178825Sdfr  memset (p, 0, 28);
433178825Sdfr
434178825Sdfr  memcpy (p + 8, cksum.checksum.data, cksum.checksum.length);
435178825Sdfr  free_Checksum (&cksum);
436178825Sdfr
437178825Sdfr  HEIMDAL_MUTEX_lock(&ctx->ctx_id_mutex);
438178825Sdfr  /* sequence number */
439178825Sdfr  krb5_auth_con_getlocalseqnumber (context,
440178825Sdfr			       ctx->auth_context,
441178825Sdfr			       &seq_number);
442178825Sdfr
443178825Sdfr  seq[0] = (seq_number >> 0)  & 0xFF;
444178825Sdfr  seq[1] = (seq_number >> 8)  & 0xFF;
445178825Sdfr  seq[2] = (seq_number >> 16) & 0xFF;
446178825Sdfr  seq[3] = (seq_number >> 24) & 0xFF;
447178825Sdfr  memset (seq + 4,
448178825Sdfr	  (ctx->more_flags & LOCAL) ? 0 : 0xFF,
449178825Sdfr	  4);
450178825Sdfr
451178825Sdfr
452178825Sdfr  ret = krb5_crypto_init(context, key, ETYPE_DES3_CBC_NONE,
453178825Sdfr			 &crypto);
454178825Sdfr  if (ret) {
455178825Sdfr      free (output_message_buffer->value);
456178825Sdfr      output_message_buffer->length = 0;
457178825Sdfr      output_message_buffer->value = NULL;
458178825Sdfr      *minor_status = ret;
459178825Sdfr      return GSS_S_FAILURE;
460178825Sdfr  }
461178825Sdfr
462178825Sdfr  {
463178825Sdfr      DES_cblock ivec;
464178825Sdfr
465178825Sdfr      memcpy (&ivec, p + 8, 8);
466178825Sdfr      ret = krb5_encrypt_ivec (context,
467178825Sdfr			       crypto,
468178825Sdfr			       KRB5_KU_USAGE_SEQ,
469178825Sdfr			       seq, 8, &encdata,
470178825Sdfr			       &ivec);
471178825Sdfr  }
472178825Sdfr  krb5_crypto_destroy (context, crypto);
473178825Sdfr  if (ret) {
474178825Sdfr      free (output_message_buffer->value);
475178825Sdfr      output_message_buffer->length = 0;
476178825Sdfr      output_message_buffer->value = NULL;
477178825Sdfr      *minor_status = ret;
478178825Sdfr      return GSS_S_FAILURE;
479178825Sdfr  }
480233294Sstas
481178825Sdfr  assert (encdata.length == 8);
482178825Sdfr
483178825Sdfr  memcpy (p, encdata.data, encdata.length);
484178825Sdfr  krb5_data_free (&encdata);
485178825Sdfr
486178825Sdfr  krb5_auth_con_setlocalseqnumber (context,
487178825Sdfr			       ctx->auth_context,
488178825Sdfr			       ++seq_number);
489178825Sdfr  HEIMDAL_MUTEX_unlock(&ctx->ctx_id_mutex);
490178825Sdfr
491178825Sdfr  /* encrypt the data */
492178825Sdfr  p += 28;
493178825Sdfr
494178825Sdfr  if(conf_req_flag) {
495178825Sdfr      krb5_data tmp;
496178825Sdfr
497178825Sdfr      ret = krb5_crypto_init(context, key,
498178825Sdfr			     ETYPE_DES3_CBC_NONE, &crypto);
499178825Sdfr      if (ret) {
500178825Sdfr	  free (output_message_buffer->value);
501178825Sdfr	  output_message_buffer->length = 0;
502178825Sdfr	  output_message_buffer->value = NULL;
503178825Sdfr	  *minor_status = ret;
504178825Sdfr	  return GSS_S_FAILURE;
505178825Sdfr      }
506178825Sdfr      ret = krb5_encrypt(context, crypto, KRB5_KU_USAGE_SEAL,
507178825Sdfr			 p, datalen, &tmp);
508178825Sdfr      krb5_crypto_destroy(context, crypto);
509178825Sdfr      if (ret) {
510178825Sdfr	  free (output_message_buffer->value);
511178825Sdfr	  output_message_buffer->length = 0;
512178825Sdfr	  output_message_buffer->value = NULL;
513178825Sdfr	  *minor_status = ret;
514178825Sdfr	  return GSS_S_FAILURE;
515178825Sdfr      }
516178825Sdfr      assert (tmp.length == datalen);
517178825Sdfr
518178825Sdfr      memcpy (p, tmp.data, datalen);
519178825Sdfr      krb5_data_free(&tmp);
520178825Sdfr  }
521178825Sdfr  if(conf_state != NULL)
522178825Sdfr      *conf_state = conf_req_flag;
523178825Sdfr  *minor_status = 0;
524178825Sdfr  return GSS_S_COMPLETE;
525178825Sdfr}
526178825Sdfr
527233294SstasOM_uint32 GSSAPI_CALLCONV
528233294Sstas_gsskrb5_wrap
529178825Sdfr           (OM_uint32 * minor_status,
530178825Sdfr            const gss_ctx_id_t context_handle,
531178825Sdfr            int conf_req_flag,
532178825Sdfr            gss_qop_t qop_req,
533178825Sdfr            const gss_buffer_t input_message_buffer,
534178825Sdfr            int * conf_state,
535178825Sdfr            gss_buffer_t output_message_buffer
536178825Sdfr           )
537178825Sdfr{
538178825Sdfr  krb5_context context;
539178825Sdfr  krb5_keyblock *key;
540178825Sdfr  OM_uint32 ret;
541178825Sdfr  krb5_keytype keytype;
542178825Sdfr  const gsskrb5_ctx ctx = (const gsskrb5_ctx) context_handle;
543178825Sdfr
544233294Sstas  output_message_buffer->value = NULL;
545233294Sstas  output_message_buffer->length = 0;
546233294Sstas
547178825Sdfr  GSSAPI_KRB5_INIT (&context);
548178825Sdfr
549233294Sstas  if (ctx->more_flags & IS_CFX)
550233294Sstas      return _gssapi_wrap_cfx (minor_status, ctx, context, conf_req_flag,
551233294Sstas			       input_message_buffer, conf_state,
552233294Sstas			       output_message_buffer);
553233294Sstas
554178825Sdfr  HEIMDAL_MUTEX_lock(&ctx->ctx_id_mutex);
555178825Sdfr  ret = _gsskrb5i_get_token_key(ctx, context, &key);
556178825Sdfr  HEIMDAL_MUTEX_unlock(&ctx->ctx_id_mutex);
557178825Sdfr  if (ret) {
558178825Sdfr      *minor_status = ret;
559178825Sdfr      return GSS_S_FAILURE;
560178825Sdfr  }
561178825Sdfr  krb5_enctype_to_keytype (context, key->keytype, &keytype);
562178825Sdfr
563178825Sdfr  switch (keytype) {
564178825Sdfr  case KEYTYPE_DES :
565233294Sstas#ifdef HEIM_WEAK_CRYPTO
566178825Sdfr      ret = wrap_des (minor_status, ctx, context, conf_req_flag,
567178825Sdfr		      qop_req, input_message_buffer, conf_state,
568178825Sdfr		      output_message_buffer, key);
569233294Sstas#else
570233294Sstas      ret = GSS_S_FAILURE;
571233294Sstas#endif
572178825Sdfr      break;
573178825Sdfr  case KEYTYPE_DES3 :
574178825Sdfr      ret = wrap_des3 (minor_status, ctx, context, conf_req_flag,
575178825Sdfr		       qop_req, input_message_buffer, conf_state,
576178825Sdfr		       output_message_buffer, key);
577178825Sdfr      break;
578178825Sdfr  case KEYTYPE_ARCFOUR:
579178825Sdfr  case KEYTYPE_ARCFOUR_56:
580178825Sdfr      ret = _gssapi_wrap_arcfour (minor_status, ctx, context, conf_req_flag,
581178825Sdfr				  qop_req, input_message_buffer, conf_state,
582178825Sdfr				  output_message_buffer, key);
583178825Sdfr      break;
584178825Sdfr  default :
585233294Sstas      abort();
586178825Sdfr      break;
587178825Sdfr  }
588178825Sdfr  krb5_free_keyblock (context, key);
589178825Sdfr  return ret;
590178825Sdfr}
591