xref: /freebsd/crypto/heimdal/lib/gssapi/krb5/wrap.c (revision c19800e8cd5640693f36f2040db4ab5e8d738146)
1c19800e8SDoug Rabson /*
2c19800e8SDoug Rabson  * Copyright (c) 1997 - 2003 Kungliga Tekniska H�gskolan
3c19800e8SDoug Rabson  * (Royal Institute of Technology, Stockholm, Sweden).
4c19800e8SDoug Rabson  * All rights reserved.
5c19800e8SDoug Rabson  *
6c19800e8SDoug Rabson  * Redistribution and use in source and binary forms, with or without
7c19800e8SDoug Rabson  * modification, are permitted provided that the following conditions
8c19800e8SDoug Rabson  * are met:
9c19800e8SDoug Rabson  *
10c19800e8SDoug Rabson  * 1. Redistributions of source code must retain the above copyright
11c19800e8SDoug Rabson  *    notice, this list of conditions and the following disclaimer.
12c19800e8SDoug Rabson  *
13c19800e8SDoug Rabson  * 2. Redistributions in binary form must reproduce the above copyright
14c19800e8SDoug Rabson  *    notice, this list of conditions and the following disclaimer in the
15c19800e8SDoug Rabson  *    documentation and/or other materials provided with the distribution.
16c19800e8SDoug Rabson  *
17c19800e8SDoug Rabson  * 3. Neither the name of the Institute nor the names of its contributors
18c19800e8SDoug Rabson  *    may be used to endorse or promote products derived from this software
19c19800e8SDoug Rabson  *    without specific prior written permission.
20c19800e8SDoug Rabson  *
21c19800e8SDoug Rabson  * THIS SOFTWARE IS PROVIDED BY THE INSTITUTE AND CONTRIBUTORS ``AS IS'' AND
22c19800e8SDoug Rabson  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
23c19800e8SDoug Rabson  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
24c19800e8SDoug Rabson  * ARE DISCLAIMED.  IN NO EVENT SHALL THE INSTITUTE OR CONTRIBUTORS BE LIABLE
25c19800e8SDoug Rabson  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
26c19800e8SDoug Rabson  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
27c19800e8SDoug Rabson  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
28c19800e8SDoug Rabson  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
29c19800e8SDoug Rabson  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
30c19800e8SDoug Rabson  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
31c19800e8SDoug Rabson  * SUCH DAMAGE.
32c19800e8SDoug Rabson  */
33c19800e8SDoug Rabson 
34c19800e8SDoug Rabson #include "krb5/gsskrb5_locl.h"
35c19800e8SDoug Rabson 
36c19800e8SDoug Rabson RCSID("$Id: wrap.c 19035 2006-11-14 09:49:56Z lha $");
37c19800e8SDoug Rabson 
38c19800e8SDoug Rabson /*
39c19800e8SDoug Rabson  * Return initiator subkey, or if that doesn't exists, the subkey.
40c19800e8SDoug Rabson  */
41c19800e8SDoug Rabson 
42c19800e8SDoug Rabson krb5_error_code
43c19800e8SDoug Rabson _gsskrb5i_get_initiator_subkey(const gsskrb5_ctx ctx,
44c19800e8SDoug Rabson 			       krb5_context context,
45c19800e8SDoug Rabson 			       krb5_keyblock **key)
46c19800e8SDoug Rabson {
47c19800e8SDoug Rabson     krb5_error_code ret;
48c19800e8SDoug Rabson     *key = NULL;
49c19800e8SDoug Rabson 
50c19800e8SDoug Rabson     if (ctx->more_flags & LOCAL) {
51c19800e8SDoug Rabson 	ret = krb5_auth_con_getlocalsubkey(context,
52c19800e8SDoug Rabson 				     ctx->auth_context,
53c19800e8SDoug Rabson 				     key);
54c19800e8SDoug Rabson     } else {
55c19800e8SDoug Rabson 	ret = krb5_auth_con_getremotesubkey(context,
56c19800e8SDoug Rabson 				      ctx->auth_context,
57c19800e8SDoug Rabson 				      key);
58c19800e8SDoug Rabson     }
59c19800e8SDoug Rabson     if (ret == 0 && *key == NULL)
60c19800e8SDoug Rabson 	ret = krb5_auth_con_getkey(context,
61c19800e8SDoug Rabson 				   ctx->auth_context,
62c19800e8SDoug Rabson 				   key);
63c19800e8SDoug Rabson     if (ret == 0 && *key == NULL) {
64c19800e8SDoug Rabson 	krb5_set_error_string(context, "No initiator subkey available");
65c19800e8SDoug Rabson 	return GSS_KRB5_S_KG_NO_SUBKEY;
66c19800e8SDoug Rabson     }
67c19800e8SDoug Rabson     return ret;
68c19800e8SDoug Rabson }
69c19800e8SDoug Rabson 
70c19800e8SDoug Rabson krb5_error_code
71c19800e8SDoug Rabson _gsskrb5i_get_acceptor_subkey(const gsskrb5_ctx ctx,
72c19800e8SDoug Rabson 			      krb5_context context,
73c19800e8SDoug Rabson 			      krb5_keyblock **key)
74c19800e8SDoug Rabson {
75c19800e8SDoug Rabson     krb5_error_code ret;
76c19800e8SDoug Rabson     *key = NULL;
77c19800e8SDoug Rabson 
78c19800e8SDoug Rabson     if (ctx->more_flags & LOCAL) {
79c19800e8SDoug Rabson 	ret = krb5_auth_con_getremotesubkey(context,
80c19800e8SDoug Rabson 				      ctx->auth_context,
81c19800e8SDoug Rabson 				      key);
82c19800e8SDoug Rabson     } else {
83c19800e8SDoug Rabson 	ret = krb5_auth_con_getlocalsubkey(context,
84c19800e8SDoug Rabson 				     ctx->auth_context,
85c19800e8SDoug Rabson 				     key);
86c19800e8SDoug Rabson     }
87c19800e8SDoug Rabson     if (ret == 0 && *key == NULL) {
88c19800e8SDoug Rabson 	krb5_set_error_string(context, "No acceptor subkey available");
89c19800e8SDoug Rabson 	return GSS_KRB5_S_KG_NO_SUBKEY;
90c19800e8SDoug Rabson     }
91c19800e8SDoug Rabson     return ret;
92c19800e8SDoug Rabson }
93c19800e8SDoug Rabson 
94c19800e8SDoug Rabson OM_uint32
95c19800e8SDoug Rabson _gsskrb5i_get_token_key(const gsskrb5_ctx ctx,
96c19800e8SDoug Rabson 			krb5_context context,
97c19800e8SDoug Rabson 			krb5_keyblock **key)
98c19800e8SDoug Rabson {
99c19800e8SDoug Rabson     _gsskrb5i_get_acceptor_subkey(ctx, context, key);
100c19800e8SDoug Rabson     if(*key == NULL) {
101c19800e8SDoug Rabson 	/*
102c19800e8SDoug Rabson 	 * Only use the initiator subkey or ticket session key if an
103c19800e8SDoug Rabson 	 * acceptor subkey was not required.
104c19800e8SDoug Rabson 	 */
105c19800e8SDoug Rabson 	if ((ctx->more_flags & ACCEPTOR_SUBKEY) == 0)
106c19800e8SDoug Rabson 	    _gsskrb5i_get_initiator_subkey(ctx, context, key);
107c19800e8SDoug Rabson     }
108c19800e8SDoug Rabson     if (*key == NULL) {
109c19800e8SDoug Rabson 	krb5_set_error_string(context, "No token key available");
110c19800e8SDoug Rabson 	return GSS_KRB5_S_KG_NO_SUBKEY;
111c19800e8SDoug Rabson     }
112c19800e8SDoug Rabson     return 0;
113c19800e8SDoug Rabson }
114c19800e8SDoug Rabson 
115c19800e8SDoug Rabson static OM_uint32
116c19800e8SDoug Rabson sub_wrap_size (
117c19800e8SDoug Rabson             OM_uint32 req_output_size,
118c19800e8SDoug Rabson             OM_uint32 * max_input_size,
119c19800e8SDoug Rabson 	    int blocksize,
120c19800e8SDoug Rabson 	    int extrasize
121c19800e8SDoug Rabson            )
122c19800e8SDoug Rabson {
123c19800e8SDoug Rabson     size_t len, total_len;
124c19800e8SDoug Rabson 
125c19800e8SDoug Rabson     len = 8 + req_output_size + blocksize + extrasize;
126c19800e8SDoug Rabson 
127c19800e8SDoug Rabson     _gsskrb5_encap_length(len, &len, &total_len, GSS_KRB5_MECHANISM);
128c19800e8SDoug Rabson 
129c19800e8SDoug Rabson     total_len -= req_output_size; /* token length */
130c19800e8SDoug Rabson     if (total_len < req_output_size) {
131c19800e8SDoug Rabson         *max_input_size = (req_output_size - total_len);
132c19800e8SDoug Rabson         (*max_input_size) &= (~(OM_uint32)(blocksize - 1));
133c19800e8SDoug Rabson     } else {
134c19800e8SDoug Rabson         *max_input_size = 0;
135c19800e8SDoug Rabson     }
136c19800e8SDoug Rabson     return GSS_S_COMPLETE;
137c19800e8SDoug Rabson }
138c19800e8SDoug Rabson 
139c19800e8SDoug Rabson OM_uint32
140c19800e8SDoug Rabson _gsskrb5_wrap_size_limit (
141c19800e8SDoug Rabson             OM_uint32 * minor_status,
142c19800e8SDoug Rabson             const gss_ctx_id_t context_handle,
143c19800e8SDoug Rabson             int conf_req_flag,
144c19800e8SDoug Rabson             gss_qop_t qop_req,
145c19800e8SDoug Rabson             OM_uint32 req_output_size,
146c19800e8SDoug Rabson             OM_uint32 * max_input_size
147c19800e8SDoug Rabson            )
148c19800e8SDoug Rabson {
149c19800e8SDoug Rabson   krb5_context context;
150c19800e8SDoug Rabson   krb5_keyblock *key;
151c19800e8SDoug Rabson   OM_uint32 ret;
152c19800e8SDoug Rabson   krb5_keytype keytype;
153c19800e8SDoug Rabson   const gsskrb5_ctx ctx = (const gsskrb5_ctx) context_handle;
154c19800e8SDoug Rabson 
155c19800e8SDoug Rabson   GSSAPI_KRB5_INIT (&context);
156c19800e8SDoug Rabson 
157c19800e8SDoug Rabson   HEIMDAL_MUTEX_lock(&ctx->ctx_id_mutex);
158c19800e8SDoug Rabson   ret = _gsskrb5i_get_token_key(ctx, context, &key);
159c19800e8SDoug Rabson   HEIMDAL_MUTEX_unlock(&ctx->ctx_id_mutex);
160c19800e8SDoug Rabson   if (ret) {
161c19800e8SDoug Rabson       *minor_status = ret;
162c19800e8SDoug Rabson       return GSS_S_FAILURE;
163c19800e8SDoug Rabson   }
164c19800e8SDoug Rabson   krb5_enctype_to_keytype (context, key->keytype, &keytype);
165c19800e8SDoug Rabson 
166c19800e8SDoug Rabson   switch (keytype) {
167c19800e8SDoug Rabson   case KEYTYPE_DES :
168c19800e8SDoug Rabson       ret = sub_wrap_size(req_output_size, max_input_size, 8, 22);
169c19800e8SDoug Rabson       break;
170c19800e8SDoug Rabson   case KEYTYPE_ARCFOUR:
171c19800e8SDoug Rabson   case KEYTYPE_ARCFOUR_56:
172c19800e8SDoug Rabson       ret = _gssapi_wrap_size_arcfour(minor_status, ctx, context,
173c19800e8SDoug Rabson 				      conf_req_flag, qop_req,
174c19800e8SDoug Rabson 				      req_output_size, max_input_size, key);
175c19800e8SDoug Rabson       break;
176c19800e8SDoug Rabson   case KEYTYPE_DES3 :
177c19800e8SDoug Rabson       ret = sub_wrap_size(req_output_size, max_input_size, 8, 34);
178c19800e8SDoug Rabson       break;
179c19800e8SDoug Rabson   default :
180c19800e8SDoug Rabson       ret = _gssapi_wrap_size_cfx(minor_status, ctx, context,
181c19800e8SDoug Rabson 				  conf_req_flag, qop_req,
182c19800e8SDoug Rabson 				  req_output_size, max_input_size, key);
183c19800e8SDoug Rabson       break;
184c19800e8SDoug Rabson   }
185c19800e8SDoug Rabson   krb5_free_keyblock (context, key);
186c19800e8SDoug Rabson   *minor_status = 0;
187c19800e8SDoug Rabson   return ret;
188c19800e8SDoug Rabson }
189c19800e8SDoug Rabson 
190c19800e8SDoug Rabson static OM_uint32
191c19800e8SDoug Rabson wrap_des
192c19800e8SDoug Rabson            (OM_uint32 * minor_status,
193c19800e8SDoug Rabson             const gsskrb5_ctx ctx,
194c19800e8SDoug Rabson 	    krb5_context context,
195c19800e8SDoug Rabson             int conf_req_flag,
196c19800e8SDoug Rabson             gss_qop_t qop_req,
197c19800e8SDoug Rabson             const gss_buffer_t input_message_buffer,
198c19800e8SDoug Rabson             int * conf_state,
199c19800e8SDoug Rabson             gss_buffer_t output_message_buffer,
200c19800e8SDoug Rabson 	    krb5_keyblock *key
201c19800e8SDoug Rabson            )
202c19800e8SDoug Rabson {
203c19800e8SDoug Rabson   u_char *p;
204c19800e8SDoug Rabson   MD5_CTX md5;
205c19800e8SDoug Rabson   u_char hash[16];
206c19800e8SDoug Rabson   DES_key_schedule schedule;
207c19800e8SDoug Rabson   DES_cblock deskey;
208c19800e8SDoug Rabson   DES_cblock zero;
209c19800e8SDoug Rabson   int i;
210c19800e8SDoug Rabson   int32_t seq_number;
211c19800e8SDoug Rabson   size_t len, total_len, padlength, datalen;
212c19800e8SDoug Rabson 
213c19800e8SDoug Rabson   padlength = 8 - (input_message_buffer->length % 8);
214c19800e8SDoug Rabson   datalen = input_message_buffer->length + padlength + 8;
215c19800e8SDoug Rabson   len = datalen + 22;
216c19800e8SDoug Rabson   _gsskrb5_encap_length (len, &len, &total_len, GSS_KRB5_MECHANISM);
217c19800e8SDoug Rabson 
218c19800e8SDoug Rabson   output_message_buffer->length = total_len;
219c19800e8SDoug Rabson   output_message_buffer->value  = malloc (total_len);
220c19800e8SDoug Rabson   if (output_message_buffer->value == NULL) {
221c19800e8SDoug Rabson     output_message_buffer->length = 0;
222c19800e8SDoug Rabson     *minor_status = ENOMEM;
223c19800e8SDoug Rabson     return GSS_S_FAILURE;
224c19800e8SDoug Rabson   }
225c19800e8SDoug Rabson 
226c19800e8SDoug Rabson   p = _gsskrb5_make_header(output_message_buffer->value,
227c19800e8SDoug Rabson 			      len,
228c19800e8SDoug Rabson 			      "\x02\x01", /* TOK_ID */
229c19800e8SDoug Rabson 			      GSS_KRB5_MECHANISM);
230c19800e8SDoug Rabson 
231c19800e8SDoug Rabson   /* SGN_ALG */
232c19800e8SDoug Rabson   memcpy (p, "\x00\x00", 2);
233c19800e8SDoug Rabson   p += 2;
234c19800e8SDoug Rabson   /* SEAL_ALG */
235c19800e8SDoug Rabson   if(conf_req_flag)
236c19800e8SDoug Rabson       memcpy (p, "\x00\x00", 2);
237c19800e8SDoug Rabson   else
238c19800e8SDoug Rabson       memcpy (p, "\xff\xff", 2);
239c19800e8SDoug Rabson   p += 2;
240c19800e8SDoug Rabson   /* Filler */
241c19800e8SDoug Rabson   memcpy (p, "\xff\xff", 2);
242c19800e8SDoug Rabson   p += 2;
243c19800e8SDoug Rabson 
244c19800e8SDoug Rabson   /* fill in later */
245c19800e8SDoug Rabson   memset (p, 0, 16);
246c19800e8SDoug Rabson   p += 16;
247c19800e8SDoug Rabson 
248c19800e8SDoug Rabson   /* confounder + data + pad */
249c19800e8SDoug Rabson   krb5_generate_random_block(p, 8);
250c19800e8SDoug Rabson   memcpy (p + 8, input_message_buffer->value,
251c19800e8SDoug Rabson 	  input_message_buffer->length);
252c19800e8SDoug Rabson   memset (p + 8 + input_message_buffer->length, padlength, padlength);
253c19800e8SDoug Rabson 
254c19800e8SDoug Rabson   /* checksum */
255c19800e8SDoug Rabson   MD5_Init (&md5);
256c19800e8SDoug Rabson   MD5_Update (&md5, p - 24, 8);
257c19800e8SDoug Rabson   MD5_Update (&md5, p, datalen);
258c19800e8SDoug Rabson   MD5_Final (hash, &md5);
259c19800e8SDoug Rabson 
260c19800e8SDoug Rabson   memset (&zero, 0, sizeof(zero));
261c19800e8SDoug Rabson   memcpy (&deskey, key->keyvalue.data, sizeof(deskey));
262c19800e8SDoug Rabson   DES_set_key (&deskey, &schedule);
263c19800e8SDoug Rabson   DES_cbc_cksum ((void *)hash, (void *)hash, sizeof(hash),
264c19800e8SDoug Rabson 		 &schedule, &zero);
265c19800e8SDoug Rabson   memcpy (p - 8, hash, 8);
266c19800e8SDoug Rabson 
267c19800e8SDoug Rabson   /* sequence number */
268c19800e8SDoug Rabson   HEIMDAL_MUTEX_lock(&ctx->ctx_id_mutex);
269c19800e8SDoug Rabson   krb5_auth_con_getlocalseqnumber (context,
270c19800e8SDoug Rabson 				   ctx->auth_context,
271c19800e8SDoug Rabson 				   &seq_number);
272c19800e8SDoug Rabson 
273c19800e8SDoug Rabson   p -= 16;
274c19800e8SDoug Rabson   p[0] = (seq_number >> 0)  & 0xFF;
275c19800e8SDoug Rabson   p[1] = (seq_number >> 8)  & 0xFF;
276c19800e8SDoug Rabson   p[2] = (seq_number >> 16) & 0xFF;
277c19800e8SDoug Rabson   p[3] = (seq_number >> 24) & 0xFF;
278c19800e8SDoug Rabson   memset (p + 4,
279c19800e8SDoug Rabson 	  (ctx->more_flags & LOCAL) ? 0 : 0xFF,
280c19800e8SDoug Rabson 	  4);
281c19800e8SDoug Rabson 
282c19800e8SDoug Rabson   DES_set_key (&deskey, &schedule);
283c19800e8SDoug Rabson   DES_cbc_encrypt ((void *)p, (void *)p, 8,
284c19800e8SDoug Rabson 		   &schedule, (DES_cblock *)(p + 8), DES_ENCRYPT);
285c19800e8SDoug Rabson 
286c19800e8SDoug Rabson   krb5_auth_con_setlocalseqnumber (context,
287c19800e8SDoug Rabson 			       ctx->auth_context,
288c19800e8SDoug Rabson 			       ++seq_number);
289c19800e8SDoug Rabson   HEIMDAL_MUTEX_unlock(&ctx->ctx_id_mutex);
290c19800e8SDoug Rabson 
291c19800e8SDoug Rabson   /* encrypt the data */
292c19800e8SDoug Rabson   p += 16;
293c19800e8SDoug Rabson 
294c19800e8SDoug Rabson   if(conf_req_flag) {
295c19800e8SDoug Rabson       memcpy (&deskey, key->keyvalue.data, sizeof(deskey));
296c19800e8SDoug Rabson 
297c19800e8SDoug Rabson       for (i = 0; i < sizeof(deskey); ++i)
298c19800e8SDoug Rabson 	  deskey[i] ^= 0xf0;
299c19800e8SDoug Rabson       DES_set_key (&deskey, &schedule);
300c19800e8SDoug Rabson       memset (&zero, 0, sizeof(zero));
301c19800e8SDoug Rabson       DES_cbc_encrypt ((void *)p,
302c19800e8SDoug Rabson 		       (void *)p,
303c19800e8SDoug Rabson 		       datalen,
304c19800e8SDoug Rabson 		       &schedule,
305c19800e8SDoug Rabson 		       &zero,
306c19800e8SDoug Rabson 		       DES_ENCRYPT);
307c19800e8SDoug Rabson   }
308c19800e8SDoug Rabson   memset (deskey, 0, sizeof(deskey));
309c19800e8SDoug Rabson   memset (&schedule, 0, sizeof(schedule));
310c19800e8SDoug Rabson 
311c19800e8SDoug Rabson   if(conf_state != NULL)
312c19800e8SDoug Rabson       *conf_state = conf_req_flag;
313c19800e8SDoug Rabson   *minor_status = 0;
314c19800e8SDoug Rabson   return GSS_S_COMPLETE;
315c19800e8SDoug Rabson }
316c19800e8SDoug Rabson 
317c19800e8SDoug Rabson static OM_uint32
318c19800e8SDoug Rabson wrap_des3
319c19800e8SDoug Rabson            (OM_uint32 * minor_status,
320c19800e8SDoug Rabson             const gsskrb5_ctx ctx,
321c19800e8SDoug Rabson 	    krb5_context context,
322c19800e8SDoug Rabson             int conf_req_flag,
323c19800e8SDoug Rabson             gss_qop_t qop_req,
324c19800e8SDoug Rabson             const gss_buffer_t input_message_buffer,
325c19800e8SDoug Rabson             int * conf_state,
326c19800e8SDoug Rabson             gss_buffer_t output_message_buffer,
327c19800e8SDoug Rabson 	    krb5_keyblock *key
328c19800e8SDoug Rabson            )
329c19800e8SDoug Rabson {
330c19800e8SDoug Rabson   u_char *p;
331c19800e8SDoug Rabson   u_char seq[8];
332c19800e8SDoug Rabson   int32_t seq_number;
333c19800e8SDoug Rabson   size_t len, total_len, padlength, datalen;
334c19800e8SDoug Rabson   uint32_t ret;
335c19800e8SDoug Rabson   krb5_crypto crypto;
336c19800e8SDoug Rabson   Checksum cksum;
337c19800e8SDoug Rabson   krb5_data encdata;
338c19800e8SDoug Rabson 
339c19800e8SDoug Rabson   padlength = 8 - (input_message_buffer->length % 8);
340c19800e8SDoug Rabson   datalen = input_message_buffer->length + padlength + 8;
341c19800e8SDoug Rabson   len = datalen + 34;
342c19800e8SDoug Rabson   _gsskrb5_encap_length (len, &len, &total_len, GSS_KRB5_MECHANISM);
343c19800e8SDoug Rabson 
344c19800e8SDoug Rabson   output_message_buffer->length = total_len;
345c19800e8SDoug Rabson   output_message_buffer->value  = malloc (total_len);
346c19800e8SDoug Rabson   if (output_message_buffer->value == NULL) {
347c19800e8SDoug Rabson     output_message_buffer->length = 0;
348c19800e8SDoug Rabson     *minor_status = ENOMEM;
349c19800e8SDoug Rabson     return GSS_S_FAILURE;
350c19800e8SDoug Rabson   }
351c19800e8SDoug Rabson 
352c19800e8SDoug Rabson   p = _gsskrb5_make_header(output_message_buffer->value,
353c19800e8SDoug Rabson 			      len,
354c19800e8SDoug Rabson 			      "\x02\x01", /* TOK_ID */
355c19800e8SDoug Rabson 			      GSS_KRB5_MECHANISM);
356c19800e8SDoug Rabson 
357c19800e8SDoug Rabson   /* SGN_ALG */
358c19800e8SDoug Rabson   memcpy (p, "\x04\x00", 2);	/* HMAC SHA1 DES3-KD */
359c19800e8SDoug Rabson   p += 2;
360c19800e8SDoug Rabson   /* SEAL_ALG */
361c19800e8SDoug Rabson   if(conf_req_flag)
362c19800e8SDoug Rabson       memcpy (p, "\x02\x00", 2); /* DES3-KD */
363c19800e8SDoug Rabson   else
364c19800e8SDoug Rabson       memcpy (p, "\xff\xff", 2);
365c19800e8SDoug Rabson   p += 2;
366c19800e8SDoug Rabson   /* Filler */
367c19800e8SDoug Rabson   memcpy (p, "\xff\xff", 2);
368c19800e8SDoug Rabson   p += 2;
369c19800e8SDoug Rabson 
370c19800e8SDoug Rabson   /* calculate checksum (the above + confounder + data + pad) */
371c19800e8SDoug Rabson 
372c19800e8SDoug Rabson   memcpy (p + 20, p - 8, 8);
373c19800e8SDoug Rabson   krb5_generate_random_block(p + 28, 8);
374c19800e8SDoug Rabson   memcpy (p + 28 + 8, input_message_buffer->value,
375c19800e8SDoug Rabson 	  input_message_buffer->length);
376c19800e8SDoug Rabson   memset (p + 28 + 8 + input_message_buffer->length, padlength, padlength);
377c19800e8SDoug Rabson 
378c19800e8SDoug Rabson   ret = krb5_crypto_init(context, key, 0, &crypto);
379c19800e8SDoug Rabson   if (ret) {
380c19800e8SDoug Rabson       free (output_message_buffer->value);
381c19800e8SDoug Rabson       output_message_buffer->length = 0;
382c19800e8SDoug Rabson       output_message_buffer->value = NULL;
383c19800e8SDoug Rabson       *minor_status = ret;
384c19800e8SDoug Rabson       return GSS_S_FAILURE;
385c19800e8SDoug Rabson   }
386c19800e8SDoug Rabson 
387c19800e8SDoug Rabson   ret = krb5_create_checksum (context,
388c19800e8SDoug Rabson 			      crypto,
389c19800e8SDoug Rabson 			      KRB5_KU_USAGE_SIGN,
390c19800e8SDoug Rabson 			      0,
391c19800e8SDoug Rabson 			      p + 20,
392c19800e8SDoug Rabson 			      datalen + 8,
393c19800e8SDoug Rabson 			      &cksum);
394c19800e8SDoug Rabson   krb5_crypto_destroy (context, crypto);
395c19800e8SDoug Rabson   if (ret) {
396c19800e8SDoug Rabson       free (output_message_buffer->value);
397c19800e8SDoug Rabson       output_message_buffer->length = 0;
398c19800e8SDoug Rabson       output_message_buffer->value = NULL;
399c19800e8SDoug Rabson       *minor_status = ret;
400c19800e8SDoug Rabson       return GSS_S_FAILURE;
401c19800e8SDoug Rabson   }
402c19800e8SDoug Rabson 
403c19800e8SDoug Rabson   /* zero out SND_SEQ + SGN_CKSUM in case */
404c19800e8SDoug Rabson   memset (p, 0, 28);
405c19800e8SDoug Rabson 
406c19800e8SDoug Rabson   memcpy (p + 8, cksum.checksum.data, cksum.checksum.length);
407c19800e8SDoug Rabson   free_Checksum (&cksum);
408c19800e8SDoug Rabson 
409c19800e8SDoug Rabson   HEIMDAL_MUTEX_lock(&ctx->ctx_id_mutex);
410c19800e8SDoug Rabson   /* sequence number */
411c19800e8SDoug Rabson   krb5_auth_con_getlocalseqnumber (context,
412c19800e8SDoug Rabson 			       ctx->auth_context,
413c19800e8SDoug Rabson 			       &seq_number);
414c19800e8SDoug Rabson 
415c19800e8SDoug Rabson   seq[0] = (seq_number >> 0)  & 0xFF;
416c19800e8SDoug Rabson   seq[1] = (seq_number >> 8)  & 0xFF;
417c19800e8SDoug Rabson   seq[2] = (seq_number >> 16) & 0xFF;
418c19800e8SDoug Rabson   seq[3] = (seq_number >> 24) & 0xFF;
419c19800e8SDoug Rabson   memset (seq + 4,
420c19800e8SDoug Rabson 	  (ctx->more_flags & LOCAL) ? 0 : 0xFF,
421c19800e8SDoug Rabson 	  4);
422c19800e8SDoug Rabson 
423c19800e8SDoug Rabson 
424c19800e8SDoug Rabson   ret = krb5_crypto_init(context, key, ETYPE_DES3_CBC_NONE,
425c19800e8SDoug Rabson 			 &crypto);
426c19800e8SDoug Rabson   if (ret) {
427c19800e8SDoug Rabson       free (output_message_buffer->value);
428c19800e8SDoug Rabson       output_message_buffer->length = 0;
429c19800e8SDoug Rabson       output_message_buffer->value = NULL;
430c19800e8SDoug Rabson       *minor_status = ret;
431c19800e8SDoug Rabson       return GSS_S_FAILURE;
432c19800e8SDoug Rabson   }
433c19800e8SDoug Rabson 
434c19800e8SDoug Rabson   {
435c19800e8SDoug Rabson       DES_cblock ivec;
436c19800e8SDoug Rabson 
437c19800e8SDoug Rabson       memcpy (&ivec, p + 8, 8);
438c19800e8SDoug Rabson       ret = krb5_encrypt_ivec (context,
439c19800e8SDoug Rabson 			       crypto,
440c19800e8SDoug Rabson 			       KRB5_KU_USAGE_SEQ,
441c19800e8SDoug Rabson 			       seq, 8, &encdata,
442c19800e8SDoug Rabson 			       &ivec);
443c19800e8SDoug Rabson   }
444c19800e8SDoug Rabson   krb5_crypto_destroy (context, crypto);
445c19800e8SDoug Rabson   if (ret) {
446c19800e8SDoug Rabson       free (output_message_buffer->value);
447c19800e8SDoug Rabson       output_message_buffer->length = 0;
448c19800e8SDoug Rabson       output_message_buffer->value = NULL;
449c19800e8SDoug Rabson       *minor_status = ret;
450c19800e8SDoug Rabson       return GSS_S_FAILURE;
451c19800e8SDoug Rabson   }
452c19800e8SDoug Rabson 
453c19800e8SDoug Rabson   assert (encdata.length == 8);
454c19800e8SDoug Rabson 
455c19800e8SDoug Rabson   memcpy (p, encdata.data, encdata.length);
456c19800e8SDoug Rabson   krb5_data_free (&encdata);
457c19800e8SDoug Rabson 
458c19800e8SDoug Rabson   krb5_auth_con_setlocalseqnumber (context,
459c19800e8SDoug Rabson 			       ctx->auth_context,
460c19800e8SDoug Rabson 			       ++seq_number);
461c19800e8SDoug Rabson   HEIMDAL_MUTEX_unlock(&ctx->ctx_id_mutex);
462c19800e8SDoug Rabson 
463c19800e8SDoug Rabson   /* encrypt the data */
464c19800e8SDoug Rabson   p += 28;
465c19800e8SDoug Rabson 
466c19800e8SDoug Rabson   if(conf_req_flag) {
467c19800e8SDoug Rabson       krb5_data tmp;
468c19800e8SDoug Rabson 
469c19800e8SDoug Rabson       ret = krb5_crypto_init(context, key,
470c19800e8SDoug Rabson 			     ETYPE_DES3_CBC_NONE, &crypto);
471c19800e8SDoug Rabson       if (ret) {
472c19800e8SDoug Rabson 	  free (output_message_buffer->value);
473c19800e8SDoug Rabson 	  output_message_buffer->length = 0;
474c19800e8SDoug Rabson 	  output_message_buffer->value = NULL;
475c19800e8SDoug Rabson 	  *minor_status = ret;
476c19800e8SDoug Rabson 	  return GSS_S_FAILURE;
477c19800e8SDoug Rabson       }
478c19800e8SDoug Rabson       ret = krb5_encrypt(context, crypto, KRB5_KU_USAGE_SEAL,
479c19800e8SDoug Rabson 			 p, datalen, &tmp);
480c19800e8SDoug Rabson       krb5_crypto_destroy(context, crypto);
481c19800e8SDoug Rabson       if (ret) {
482c19800e8SDoug Rabson 	  free (output_message_buffer->value);
483c19800e8SDoug Rabson 	  output_message_buffer->length = 0;
484c19800e8SDoug Rabson 	  output_message_buffer->value = NULL;
485c19800e8SDoug Rabson 	  *minor_status = ret;
486c19800e8SDoug Rabson 	  return GSS_S_FAILURE;
487c19800e8SDoug Rabson       }
488c19800e8SDoug Rabson       assert (tmp.length == datalen);
489c19800e8SDoug Rabson 
490c19800e8SDoug Rabson       memcpy (p, tmp.data, datalen);
491c19800e8SDoug Rabson       krb5_data_free(&tmp);
492c19800e8SDoug Rabson   }
493c19800e8SDoug Rabson   if(conf_state != NULL)
494c19800e8SDoug Rabson       *conf_state = conf_req_flag;
495c19800e8SDoug Rabson   *minor_status = 0;
496c19800e8SDoug Rabson   return GSS_S_COMPLETE;
497c19800e8SDoug Rabson }
498c19800e8SDoug Rabson 
499c19800e8SDoug Rabson OM_uint32 _gsskrb5_wrap
500c19800e8SDoug Rabson            (OM_uint32 * minor_status,
501c19800e8SDoug Rabson             const gss_ctx_id_t context_handle,
502c19800e8SDoug Rabson             int conf_req_flag,
503c19800e8SDoug Rabson             gss_qop_t qop_req,
504c19800e8SDoug Rabson             const gss_buffer_t input_message_buffer,
505c19800e8SDoug Rabson             int * conf_state,
506c19800e8SDoug Rabson             gss_buffer_t output_message_buffer
507c19800e8SDoug Rabson            )
508c19800e8SDoug Rabson {
509c19800e8SDoug Rabson   krb5_context context;
510c19800e8SDoug Rabson   krb5_keyblock *key;
511c19800e8SDoug Rabson   OM_uint32 ret;
512c19800e8SDoug Rabson   krb5_keytype keytype;
513c19800e8SDoug Rabson   const gsskrb5_ctx ctx = (const gsskrb5_ctx) context_handle;
514c19800e8SDoug Rabson 
515c19800e8SDoug Rabson   GSSAPI_KRB5_INIT (&context);
516c19800e8SDoug Rabson 
517c19800e8SDoug Rabson   HEIMDAL_MUTEX_lock(&ctx->ctx_id_mutex);
518c19800e8SDoug Rabson   ret = _gsskrb5i_get_token_key(ctx, context, &key);
519c19800e8SDoug Rabson   HEIMDAL_MUTEX_unlock(&ctx->ctx_id_mutex);
520c19800e8SDoug Rabson   if (ret) {
521c19800e8SDoug Rabson       *minor_status = ret;
522c19800e8SDoug Rabson       return GSS_S_FAILURE;
523c19800e8SDoug Rabson   }
524c19800e8SDoug Rabson   krb5_enctype_to_keytype (context, key->keytype, &keytype);
525c19800e8SDoug Rabson 
526c19800e8SDoug Rabson   switch (keytype) {
527c19800e8SDoug Rabson   case KEYTYPE_DES :
528c19800e8SDoug Rabson       ret = wrap_des (minor_status, ctx, context, conf_req_flag,
529c19800e8SDoug Rabson 		      qop_req, input_message_buffer, conf_state,
530c19800e8SDoug Rabson 		      output_message_buffer, key);
531c19800e8SDoug Rabson       break;
532c19800e8SDoug Rabson   case KEYTYPE_DES3 :
533c19800e8SDoug Rabson       ret = wrap_des3 (minor_status, ctx, context, conf_req_flag,
534c19800e8SDoug Rabson 		       qop_req, input_message_buffer, conf_state,
535c19800e8SDoug Rabson 		       output_message_buffer, key);
536c19800e8SDoug Rabson       break;
537c19800e8SDoug Rabson   case KEYTYPE_ARCFOUR:
538c19800e8SDoug Rabson   case KEYTYPE_ARCFOUR_56:
539c19800e8SDoug Rabson       ret = _gssapi_wrap_arcfour (minor_status, ctx, context, conf_req_flag,
540c19800e8SDoug Rabson 				  qop_req, input_message_buffer, conf_state,
541c19800e8SDoug Rabson 				  output_message_buffer, key);
542c19800e8SDoug Rabson       break;
543c19800e8SDoug Rabson   default :
544c19800e8SDoug Rabson       ret = _gssapi_wrap_cfx (minor_status, ctx, context, conf_req_flag,
545c19800e8SDoug Rabson 			      qop_req, input_message_buffer, conf_state,
546c19800e8SDoug Rabson 			      output_message_buffer, key);
547c19800e8SDoug Rabson       break;
548c19800e8SDoug Rabson   }
549c19800e8SDoug Rabson   krb5_free_keyblock (context, key);
550c19800e8SDoug Rabson   return ret;
551c19800e8SDoug Rabson }
552