xref: /freebsd/crypto/heimdal/lib/gssapi/krb5/wrap.c (revision c6879c6c14eedbd060ba588a3129a6c60ebbe783)
1c19800e8SDoug Rabson /*
2ae771770SStanislav Sedov  * 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 
34ae771770SStanislav Sedov #include "gsskrb5_locl.h"
35c19800e8SDoug Rabson 
36c19800e8SDoug Rabson /*
37c19800e8SDoug Rabson  * Return initiator subkey, or if that doesn't exists, the subkey.
38c19800e8SDoug Rabson  */
39c19800e8SDoug Rabson 
40c19800e8SDoug Rabson krb5_error_code
_gsskrb5i_get_initiator_subkey(const gsskrb5_ctx ctx,krb5_context context,krb5_keyblock ** key)41c19800e8SDoug Rabson _gsskrb5i_get_initiator_subkey(const gsskrb5_ctx ctx,
42c19800e8SDoug Rabson 			       krb5_context context,
43c19800e8SDoug Rabson 			       krb5_keyblock **key)
44c19800e8SDoug Rabson {
45c19800e8SDoug Rabson     krb5_error_code ret;
46c19800e8SDoug Rabson     *key = NULL;
47c19800e8SDoug Rabson 
48c19800e8SDoug Rabson     if (ctx->more_flags & LOCAL) {
49c19800e8SDoug Rabson 	ret = krb5_auth_con_getlocalsubkey(context,
50c19800e8SDoug Rabson 				     ctx->auth_context,
51c19800e8SDoug Rabson 				     key);
52c19800e8SDoug Rabson     } else {
53c19800e8SDoug Rabson 	ret = krb5_auth_con_getremotesubkey(context,
54c19800e8SDoug Rabson 				      ctx->auth_context,
55c19800e8SDoug Rabson 				      key);
56c19800e8SDoug Rabson     }
57c19800e8SDoug Rabson     if (ret == 0 && *key == NULL)
58c19800e8SDoug Rabson 	ret = krb5_auth_con_getkey(context,
59c19800e8SDoug Rabson 				   ctx->auth_context,
60c19800e8SDoug Rabson 				   key);
61c19800e8SDoug Rabson     if (ret == 0 && *key == NULL) {
62ae771770SStanislav Sedov 	krb5_set_error_message(context, 0, "No initiator subkey available");
63c19800e8SDoug Rabson 	return GSS_KRB5_S_KG_NO_SUBKEY;
64c19800e8SDoug Rabson     }
65c19800e8SDoug Rabson     return ret;
66c19800e8SDoug Rabson }
67c19800e8SDoug Rabson 
68c19800e8SDoug Rabson krb5_error_code
_gsskrb5i_get_acceptor_subkey(const gsskrb5_ctx ctx,krb5_context context,krb5_keyblock ** key)69c19800e8SDoug Rabson _gsskrb5i_get_acceptor_subkey(const gsskrb5_ctx ctx,
70c19800e8SDoug Rabson 			      krb5_context context,
71c19800e8SDoug Rabson 			      krb5_keyblock **key)
72c19800e8SDoug Rabson {
73c19800e8SDoug Rabson     krb5_error_code ret;
74c19800e8SDoug Rabson     *key = NULL;
75c19800e8SDoug Rabson 
76c19800e8SDoug Rabson     if (ctx->more_flags & LOCAL) {
77c19800e8SDoug Rabson 	ret = krb5_auth_con_getremotesubkey(context,
78c19800e8SDoug Rabson 				      ctx->auth_context,
79c19800e8SDoug Rabson 				      key);
80c19800e8SDoug Rabson     } else {
81c19800e8SDoug Rabson 	ret = krb5_auth_con_getlocalsubkey(context,
82c19800e8SDoug Rabson 				     ctx->auth_context,
83c19800e8SDoug Rabson 				     key);
84c19800e8SDoug Rabson     }
85c19800e8SDoug Rabson     if (ret == 0 && *key == NULL) {
86ae771770SStanislav Sedov 	krb5_set_error_message(context, 0, "No acceptor subkey available");
87c19800e8SDoug Rabson 	return GSS_KRB5_S_KG_NO_SUBKEY;
88c19800e8SDoug Rabson     }
89c19800e8SDoug Rabson     return ret;
90c19800e8SDoug Rabson }
91c19800e8SDoug Rabson 
92c19800e8SDoug Rabson OM_uint32
_gsskrb5i_get_token_key(const gsskrb5_ctx ctx,krb5_context context,krb5_keyblock ** key)93c19800e8SDoug Rabson _gsskrb5i_get_token_key(const gsskrb5_ctx ctx,
94c19800e8SDoug Rabson 			krb5_context context,
95c19800e8SDoug Rabson 			krb5_keyblock **key)
96c19800e8SDoug Rabson {
97c19800e8SDoug Rabson     _gsskrb5i_get_acceptor_subkey(ctx, context, key);
98c19800e8SDoug Rabson     if(*key == NULL) {
99c19800e8SDoug Rabson 	/*
100c19800e8SDoug Rabson 	 * Only use the initiator subkey or ticket session key if an
101c19800e8SDoug Rabson 	 * acceptor subkey was not required.
102c19800e8SDoug Rabson 	 */
103c19800e8SDoug Rabson 	if ((ctx->more_flags & ACCEPTOR_SUBKEY) == 0)
104c19800e8SDoug Rabson 	    _gsskrb5i_get_initiator_subkey(ctx, context, key);
105c19800e8SDoug Rabson     }
106c19800e8SDoug Rabson     if (*key == NULL) {
107ae771770SStanislav Sedov 	krb5_set_error_message(context, 0, "No token key available");
108c19800e8SDoug Rabson 	return GSS_KRB5_S_KG_NO_SUBKEY;
109c19800e8SDoug Rabson     }
110c19800e8SDoug Rabson     return 0;
111c19800e8SDoug Rabson }
112c19800e8SDoug Rabson 
113c19800e8SDoug Rabson static OM_uint32
sub_wrap_size(OM_uint32 req_output_size,OM_uint32 * max_input_size,int blocksize,int extrasize)114c19800e8SDoug Rabson sub_wrap_size (
115c19800e8SDoug Rabson             OM_uint32 req_output_size,
116c19800e8SDoug Rabson             OM_uint32 * max_input_size,
117c19800e8SDoug Rabson 	    int blocksize,
118c19800e8SDoug Rabson 	    int extrasize
119c19800e8SDoug Rabson            )
120c19800e8SDoug Rabson {
121c19800e8SDoug Rabson     size_t len, total_len;
122c19800e8SDoug Rabson 
123c19800e8SDoug Rabson     len = 8 + req_output_size + blocksize + extrasize;
124c19800e8SDoug Rabson 
125c19800e8SDoug Rabson     _gsskrb5_encap_length(len, &len, &total_len, GSS_KRB5_MECHANISM);
126c19800e8SDoug Rabson 
127c19800e8SDoug Rabson     total_len -= req_output_size; /* token length */
128c19800e8SDoug Rabson     if (total_len < req_output_size) {
129c19800e8SDoug Rabson         *max_input_size = (req_output_size - total_len);
130c19800e8SDoug Rabson         (*max_input_size) &= (~(OM_uint32)(blocksize - 1));
131c19800e8SDoug Rabson     } else {
132c19800e8SDoug Rabson         *max_input_size = 0;
133c19800e8SDoug Rabson     }
134c19800e8SDoug Rabson     return GSS_S_COMPLETE;
135c19800e8SDoug Rabson }
136c19800e8SDoug Rabson 
137ae771770SStanislav Sedov OM_uint32 GSSAPI_CALLCONV
_gsskrb5_wrap_size_limit(OM_uint32 * minor_status,const gss_ctx_id_t context_handle,int conf_req_flag,gss_qop_t qop_req,OM_uint32 req_output_size,OM_uint32 * max_input_size)138c19800e8SDoug Rabson _gsskrb5_wrap_size_limit (
139c19800e8SDoug Rabson             OM_uint32 * minor_status,
140c19800e8SDoug Rabson             const gss_ctx_id_t context_handle,
141c19800e8SDoug Rabson             int conf_req_flag,
142c19800e8SDoug Rabson             gss_qop_t qop_req,
143c19800e8SDoug Rabson             OM_uint32 req_output_size,
144c19800e8SDoug Rabson             OM_uint32 * max_input_size
145c19800e8SDoug Rabson            )
146c19800e8SDoug Rabson {
147c19800e8SDoug Rabson   krb5_context context;
148c19800e8SDoug Rabson   krb5_keyblock *key;
149c19800e8SDoug Rabson   OM_uint32 ret;
150c19800e8SDoug Rabson   krb5_keytype keytype;
151c19800e8SDoug Rabson   const gsskrb5_ctx ctx = (const gsskrb5_ctx) context_handle;
152c19800e8SDoug Rabson 
153c19800e8SDoug Rabson   GSSAPI_KRB5_INIT (&context);
154c19800e8SDoug Rabson 
155ae771770SStanislav Sedov   if (ctx->more_flags & IS_CFX)
156ae771770SStanislav Sedov       return _gssapi_wrap_size_cfx(minor_status, ctx, context,
157ae771770SStanislav Sedov 				   conf_req_flag, qop_req,
158ae771770SStanislav Sedov 				   req_output_size, max_input_size);
159ae771770SStanislav Sedov 
160c19800e8SDoug Rabson   HEIMDAL_MUTEX_lock(&ctx->ctx_id_mutex);
161c19800e8SDoug Rabson   ret = _gsskrb5i_get_token_key(ctx, context, &key);
162c19800e8SDoug Rabson   HEIMDAL_MUTEX_unlock(&ctx->ctx_id_mutex);
163c19800e8SDoug Rabson   if (ret) {
164c19800e8SDoug Rabson       *minor_status = ret;
165c19800e8SDoug Rabson       return GSS_S_FAILURE;
166c19800e8SDoug Rabson   }
167c19800e8SDoug Rabson   krb5_enctype_to_keytype (context, key->keytype, &keytype);
168c19800e8SDoug Rabson 
169c19800e8SDoug Rabson   switch (keytype) {
170c19800e8SDoug Rabson   case KEYTYPE_DES :
171ae771770SStanislav Sedov #ifdef HEIM_WEAK_CRYPTO
172c19800e8SDoug Rabson       ret = sub_wrap_size(req_output_size, max_input_size, 8, 22);
173ae771770SStanislav Sedov #else
174ae771770SStanislav Sedov       ret = GSS_S_FAILURE;
175ae771770SStanislav Sedov #endif
176c19800e8SDoug Rabson       break;
177ae771770SStanislav Sedov   case ENCTYPE_ARCFOUR_HMAC_MD5:
178ae771770SStanislav Sedov   case ENCTYPE_ARCFOUR_HMAC_MD5_56:
179c19800e8SDoug Rabson       ret = _gssapi_wrap_size_arcfour(minor_status, ctx, context,
180c19800e8SDoug Rabson 				      conf_req_flag, qop_req,
181c19800e8SDoug Rabson 				      req_output_size, max_input_size, key);
182c19800e8SDoug Rabson       break;
183c19800e8SDoug Rabson   case KEYTYPE_DES3 :
184c19800e8SDoug Rabson       ret = sub_wrap_size(req_output_size, max_input_size, 8, 34);
185c19800e8SDoug Rabson       break;
186c19800e8SDoug Rabson   default :
187ae771770SStanislav Sedov       abort();
188c19800e8SDoug Rabson       break;
189c19800e8SDoug Rabson   }
190c19800e8SDoug Rabson   krb5_free_keyblock (context, key);
191c19800e8SDoug Rabson   *minor_status = 0;
192c19800e8SDoug Rabson   return ret;
193c19800e8SDoug Rabson }
194c19800e8SDoug Rabson 
195ae771770SStanislav Sedov #ifdef HEIM_WEAK_CRYPTO
196ae771770SStanislav Sedov 
197c19800e8SDoug Rabson static OM_uint32
wrap_des(OM_uint32 * minor_status,const gsskrb5_ctx ctx,krb5_context context,int conf_req_flag,gss_qop_t qop_req,const gss_buffer_t input_message_buffer,int * conf_state,gss_buffer_t output_message_buffer,krb5_keyblock * key)198c19800e8SDoug Rabson wrap_des
199c19800e8SDoug Rabson            (OM_uint32 * minor_status,
200c19800e8SDoug Rabson             const gsskrb5_ctx ctx,
201c19800e8SDoug Rabson 	    krb5_context context,
202c19800e8SDoug Rabson             int conf_req_flag,
203c19800e8SDoug Rabson             gss_qop_t qop_req,
204c19800e8SDoug Rabson             const gss_buffer_t input_message_buffer,
205c19800e8SDoug Rabson             int * conf_state,
206c19800e8SDoug Rabson             gss_buffer_t output_message_buffer,
207c19800e8SDoug Rabson 	    krb5_keyblock *key
208c19800e8SDoug Rabson            )
209c19800e8SDoug Rabson {
210c19800e8SDoug Rabson   u_char *p;
211ae771770SStanislav Sedov   EVP_MD_CTX *md5;
212c19800e8SDoug Rabson   u_char hash[16];
213c19800e8SDoug Rabson   DES_key_schedule schedule;
214*e4456411SJohn Baldwin   EVP_CIPHER_CTX *des_ctx;
215c19800e8SDoug Rabson   DES_cblock deskey;
216c19800e8SDoug Rabson   DES_cblock zero;
217ae771770SStanislav Sedov   size_t i;
218c19800e8SDoug Rabson   int32_t seq_number;
219c19800e8SDoug Rabson   size_t len, total_len, padlength, datalen;
220c19800e8SDoug Rabson 
221ae771770SStanislav Sedov   if (IS_DCE_STYLE(ctx)) {
222ae771770SStanislav Sedov     padlength = 0;
223ae771770SStanislav Sedov     datalen = input_message_buffer->length;
224ae771770SStanislav Sedov     len = 22 + 8;
225ae771770SStanislav Sedov     _gsskrb5_encap_length (len, &len, &total_len, GSS_KRB5_MECHANISM);
226ae771770SStanislav Sedov     total_len += datalen;
227ae771770SStanislav Sedov     datalen += 8;
228ae771770SStanislav Sedov   } else {
229c19800e8SDoug Rabson     padlength = 8 - (input_message_buffer->length % 8);
230c19800e8SDoug Rabson     datalen = input_message_buffer->length + padlength + 8;
231c19800e8SDoug Rabson     len = datalen + 22;
232c19800e8SDoug Rabson     _gsskrb5_encap_length (len, &len, &total_len, GSS_KRB5_MECHANISM);
233ae771770SStanislav Sedov   }
234c19800e8SDoug Rabson 
235c19800e8SDoug Rabson   output_message_buffer->length = total_len;
236c19800e8SDoug Rabson   output_message_buffer->value  = malloc (total_len);
237c19800e8SDoug Rabson   if (output_message_buffer->value == NULL) {
238c19800e8SDoug Rabson     output_message_buffer->length = 0;
239c19800e8SDoug Rabson     *minor_status = ENOMEM;
240c19800e8SDoug Rabson     return GSS_S_FAILURE;
241c19800e8SDoug Rabson   }
242c19800e8SDoug Rabson 
243c19800e8SDoug Rabson   p = _gsskrb5_make_header(output_message_buffer->value,
244c19800e8SDoug Rabson 			      len,
245c19800e8SDoug Rabson 			      "\x02\x01", /* TOK_ID */
246c19800e8SDoug Rabson 			      GSS_KRB5_MECHANISM);
247c19800e8SDoug Rabson 
248c19800e8SDoug Rabson   /* SGN_ALG */
249c19800e8SDoug Rabson   memcpy (p, "\x00\x00", 2);
250c19800e8SDoug Rabson   p += 2;
251c19800e8SDoug Rabson   /* SEAL_ALG */
252c19800e8SDoug Rabson   if(conf_req_flag)
253c19800e8SDoug Rabson       memcpy (p, "\x00\x00", 2);
254c19800e8SDoug Rabson   else
255c19800e8SDoug Rabson       memcpy (p, "\xff\xff", 2);
256c19800e8SDoug Rabson   p += 2;
257c19800e8SDoug Rabson   /* Filler */
258c19800e8SDoug Rabson   memcpy (p, "\xff\xff", 2);
259c19800e8SDoug Rabson   p += 2;
260c19800e8SDoug Rabson 
261c19800e8SDoug Rabson   /* fill in later */
262c19800e8SDoug Rabson   memset (p, 0, 16);
263c19800e8SDoug Rabson   p += 16;
264c19800e8SDoug Rabson 
265c19800e8SDoug Rabson   /* confounder + data + pad */
266c19800e8SDoug Rabson   krb5_generate_random_block(p, 8);
267c19800e8SDoug Rabson   memcpy (p + 8, input_message_buffer->value,
268c19800e8SDoug Rabson 	  input_message_buffer->length);
269c19800e8SDoug Rabson   memset (p + 8 + input_message_buffer->length, padlength, padlength);
270c19800e8SDoug Rabson 
271c19800e8SDoug Rabson   /* checksum */
272ae771770SStanislav Sedov   md5 = EVP_MD_CTX_create();
273ae771770SStanislav Sedov   EVP_DigestInit_ex(md5, EVP_md5(), NULL);
274ae771770SStanislav Sedov   EVP_DigestUpdate(md5, p - 24, 8);
275ae771770SStanislav Sedov   EVP_DigestUpdate(md5, p, datalen);
276ae771770SStanislav Sedov   EVP_DigestFinal_ex(md5, hash, NULL);
277ae771770SStanislav Sedov   EVP_MD_CTX_destroy(md5);
278c19800e8SDoug Rabson 
279c19800e8SDoug Rabson   memset (&zero, 0, sizeof(zero));
280c19800e8SDoug Rabson   memcpy (&deskey, key->keyvalue.data, sizeof(deskey));
281ae771770SStanislav Sedov   DES_set_key_unchecked (&deskey, &schedule);
282c19800e8SDoug Rabson   DES_cbc_cksum ((void *)hash, (void *)hash, sizeof(hash),
283c19800e8SDoug Rabson 		 &schedule, &zero);
284c19800e8SDoug Rabson   memcpy (p - 8, hash, 8);
285c19800e8SDoug Rabson 
286*e4456411SJohn Baldwin   des_ctx = EVP_CIPHER_CTX_new();
287*e4456411SJohn Baldwin   if (des_ctx == NULL) {
288*e4456411SJohn Baldwin     memset (deskey, 0, sizeof(deskey));
289*e4456411SJohn Baldwin     memset (&schedule, 0, sizeof(schedule));
290*e4456411SJohn Baldwin     free(output_message_buffer->value);
291*e4456411SJohn Baldwin     output_message_buffer->value = NULL;
292*e4456411SJohn Baldwin     output_message_buffer->length = 0;
293*e4456411SJohn Baldwin     *minor_status = ENOMEM;
294*e4456411SJohn Baldwin     return GSS_S_FAILURE;
295*e4456411SJohn Baldwin   }
296*e4456411SJohn Baldwin 
297c19800e8SDoug Rabson   /* sequence number */
298c19800e8SDoug Rabson   HEIMDAL_MUTEX_lock(&ctx->ctx_id_mutex);
299c19800e8SDoug Rabson   krb5_auth_con_getlocalseqnumber (context,
300c19800e8SDoug Rabson 				   ctx->auth_context,
301c19800e8SDoug Rabson 				   &seq_number);
302c19800e8SDoug Rabson 
303c19800e8SDoug Rabson   p -= 16;
304c19800e8SDoug Rabson   p[0] = (seq_number >> 0)  & 0xFF;
305c19800e8SDoug Rabson   p[1] = (seq_number >> 8)  & 0xFF;
306c19800e8SDoug Rabson   p[2] = (seq_number >> 16) & 0xFF;
307c19800e8SDoug Rabson   p[3] = (seq_number >> 24) & 0xFF;
308c19800e8SDoug Rabson   memset (p + 4,
309c19800e8SDoug Rabson 	  (ctx->more_flags & LOCAL) ? 0 : 0xFF,
310c19800e8SDoug Rabson 	  4);
311c19800e8SDoug Rabson 
312*e4456411SJohn Baldwin   EVP_CipherInit_ex(des_ctx, EVP_des_cbc(), NULL, key->keyvalue.data, p + 8, 1);
313*e4456411SJohn Baldwin   EVP_Cipher(des_ctx, p, p, 8);
314c19800e8SDoug Rabson 
315c19800e8SDoug Rabson   krb5_auth_con_setlocalseqnumber (context,
316c19800e8SDoug Rabson 			       ctx->auth_context,
317c19800e8SDoug Rabson 			       ++seq_number);
318c19800e8SDoug Rabson   HEIMDAL_MUTEX_unlock(&ctx->ctx_id_mutex);
319c19800e8SDoug Rabson 
320c19800e8SDoug Rabson   /* encrypt the data */
321c19800e8SDoug Rabson   p += 16;
322c19800e8SDoug Rabson 
323c19800e8SDoug Rabson   if(conf_req_flag) {
324c19800e8SDoug Rabson       memcpy (&deskey, key->keyvalue.data, sizeof(deskey));
325c19800e8SDoug Rabson 
326c19800e8SDoug Rabson       for (i = 0; i < sizeof(deskey); ++i)
327c19800e8SDoug Rabson 	  deskey[i] ^= 0xf0;
328ae771770SStanislav Sedov 
329*e4456411SJohn Baldwin       EVP_CIPHER_CTX_reset(des_ctx);
330*e4456411SJohn Baldwin       EVP_CipherInit_ex(des_ctx, EVP_des_cbc(), NULL, deskey, zero, 1);
331*e4456411SJohn Baldwin       EVP_Cipher(des_ctx, p, p, datalen);
332c19800e8SDoug Rabson   }
333*e4456411SJohn Baldwin   EVP_CIPHER_CTX_free(des_ctx);
334c19800e8SDoug Rabson   memset (deskey, 0, sizeof(deskey));
335c19800e8SDoug Rabson   memset (&schedule, 0, sizeof(schedule));
336c19800e8SDoug Rabson 
337c19800e8SDoug Rabson   if(conf_state != NULL)
338c19800e8SDoug Rabson       *conf_state = conf_req_flag;
339c19800e8SDoug Rabson   *minor_status = 0;
340c19800e8SDoug Rabson   return GSS_S_COMPLETE;
341c19800e8SDoug Rabson }
342c19800e8SDoug Rabson 
343ae771770SStanislav Sedov #endif
344ae771770SStanislav Sedov 
345c19800e8SDoug Rabson static OM_uint32
wrap_des3(OM_uint32 * minor_status,const gsskrb5_ctx ctx,krb5_context context,int conf_req_flag,gss_qop_t qop_req,const gss_buffer_t input_message_buffer,int * conf_state,gss_buffer_t output_message_buffer,krb5_keyblock * key)346c19800e8SDoug Rabson wrap_des3
347c19800e8SDoug Rabson            (OM_uint32 * minor_status,
348c19800e8SDoug Rabson             const gsskrb5_ctx ctx,
349c19800e8SDoug Rabson 	    krb5_context context,
350c19800e8SDoug Rabson             int conf_req_flag,
351c19800e8SDoug Rabson             gss_qop_t qop_req,
352c19800e8SDoug Rabson             const gss_buffer_t input_message_buffer,
353c19800e8SDoug Rabson             int * conf_state,
354c19800e8SDoug Rabson             gss_buffer_t output_message_buffer,
355c19800e8SDoug Rabson 	    krb5_keyblock *key
356c19800e8SDoug Rabson            )
357c19800e8SDoug Rabson {
358c19800e8SDoug Rabson   u_char *p;
359c19800e8SDoug Rabson   u_char seq[8];
360c19800e8SDoug Rabson   int32_t seq_number;
361c19800e8SDoug Rabson   size_t len, total_len, padlength, datalen;
362c19800e8SDoug Rabson   uint32_t ret;
363c19800e8SDoug Rabson   krb5_crypto crypto;
364c19800e8SDoug Rabson   Checksum cksum;
365c19800e8SDoug Rabson   krb5_data encdata;
366c19800e8SDoug Rabson 
367ae771770SStanislav Sedov   if (IS_DCE_STYLE(ctx)) {
368ae771770SStanislav Sedov     padlength = 0;
369ae771770SStanislav Sedov     datalen = input_message_buffer->length;
370ae771770SStanislav Sedov     len = 34 + 8;
371ae771770SStanislav Sedov     _gsskrb5_encap_length (len, &len, &total_len, GSS_KRB5_MECHANISM);
372ae771770SStanislav Sedov     total_len += datalen;
373ae771770SStanislav Sedov     datalen += 8;
374ae771770SStanislav Sedov   } else {
375c19800e8SDoug Rabson     padlength = 8 - (input_message_buffer->length % 8);
376c19800e8SDoug Rabson     datalen = input_message_buffer->length + padlength + 8;
377c19800e8SDoug Rabson     len = datalen + 34;
378c19800e8SDoug Rabson     _gsskrb5_encap_length (len, &len, &total_len, GSS_KRB5_MECHANISM);
379ae771770SStanislav Sedov   }
380c19800e8SDoug Rabson 
381c19800e8SDoug Rabson   output_message_buffer->length = total_len;
382c19800e8SDoug Rabson   output_message_buffer->value  = malloc (total_len);
383c19800e8SDoug Rabson   if (output_message_buffer->value == NULL) {
384c19800e8SDoug Rabson     output_message_buffer->length = 0;
385c19800e8SDoug Rabson     *minor_status = ENOMEM;
386c19800e8SDoug Rabson     return GSS_S_FAILURE;
387c19800e8SDoug Rabson   }
388c19800e8SDoug Rabson 
389c19800e8SDoug Rabson   p = _gsskrb5_make_header(output_message_buffer->value,
390c19800e8SDoug Rabson 			      len,
391c19800e8SDoug Rabson 			      "\x02\x01", /* TOK_ID */
392c19800e8SDoug Rabson 			      GSS_KRB5_MECHANISM);
393c19800e8SDoug Rabson 
394c19800e8SDoug Rabson   /* SGN_ALG */
395c19800e8SDoug Rabson   memcpy (p, "\x04\x00", 2);	/* HMAC SHA1 DES3-KD */
396c19800e8SDoug Rabson   p += 2;
397c19800e8SDoug Rabson   /* SEAL_ALG */
398c19800e8SDoug Rabson   if(conf_req_flag)
399c19800e8SDoug Rabson       memcpy (p, "\x02\x00", 2); /* DES3-KD */
400c19800e8SDoug Rabson   else
401c19800e8SDoug Rabson       memcpy (p, "\xff\xff", 2);
402c19800e8SDoug Rabson   p += 2;
403c19800e8SDoug Rabson   /* Filler */
404c19800e8SDoug Rabson   memcpy (p, "\xff\xff", 2);
405c19800e8SDoug Rabson   p += 2;
406c19800e8SDoug Rabson 
407c19800e8SDoug Rabson   /* calculate checksum (the above + confounder + data + pad) */
408c19800e8SDoug Rabson 
409c19800e8SDoug Rabson   memcpy (p + 20, p - 8, 8);
410c19800e8SDoug Rabson   krb5_generate_random_block(p + 28, 8);
411c19800e8SDoug Rabson   memcpy (p + 28 + 8, input_message_buffer->value,
412c19800e8SDoug Rabson 	  input_message_buffer->length);
413c19800e8SDoug Rabson   memset (p + 28 + 8 + input_message_buffer->length, padlength, padlength);
414c19800e8SDoug Rabson 
415c19800e8SDoug Rabson   ret = krb5_crypto_init(context, key, 0, &crypto);
416c19800e8SDoug Rabson   if (ret) {
417c19800e8SDoug Rabson       free (output_message_buffer->value);
418c19800e8SDoug Rabson       output_message_buffer->length = 0;
419c19800e8SDoug Rabson       output_message_buffer->value = NULL;
420c19800e8SDoug Rabson       *minor_status = ret;
421c19800e8SDoug Rabson       return GSS_S_FAILURE;
422c19800e8SDoug Rabson   }
423c19800e8SDoug Rabson 
424c19800e8SDoug Rabson   ret = krb5_create_checksum (context,
425c19800e8SDoug Rabson 			      crypto,
426c19800e8SDoug Rabson 			      KRB5_KU_USAGE_SIGN,
427c19800e8SDoug Rabson 			      0,
428c19800e8SDoug Rabson 			      p + 20,
429c19800e8SDoug Rabson 			      datalen + 8,
430c19800e8SDoug Rabson 			      &cksum);
431c19800e8SDoug Rabson   krb5_crypto_destroy (context, crypto);
432c19800e8SDoug Rabson   if (ret) {
433c19800e8SDoug Rabson       free (output_message_buffer->value);
434c19800e8SDoug Rabson       output_message_buffer->length = 0;
435c19800e8SDoug Rabson       output_message_buffer->value = NULL;
436c19800e8SDoug Rabson       *minor_status = ret;
437c19800e8SDoug Rabson       return GSS_S_FAILURE;
438c19800e8SDoug Rabson   }
439c19800e8SDoug Rabson 
440c19800e8SDoug Rabson   /* zero out SND_SEQ + SGN_CKSUM in case */
441c19800e8SDoug Rabson   memset (p, 0, 28);
442c19800e8SDoug Rabson 
443c19800e8SDoug Rabson   memcpy (p + 8, cksum.checksum.data, cksum.checksum.length);
444c19800e8SDoug Rabson   free_Checksum (&cksum);
445c19800e8SDoug Rabson 
446c19800e8SDoug Rabson   HEIMDAL_MUTEX_lock(&ctx->ctx_id_mutex);
447c19800e8SDoug Rabson   /* sequence number */
448c19800e8SDoug Rabson   krb5_auth_con_getlocalseqnumber (context,
449c19800e8SDoug Rabson 			       ctx->auth_context,
450c19800e8SDoug Rabson 			       &seq_number);
451c19800e8SDoug Rabson 
452c19800e8SDoug Rabson   seq[0] = (seq_number >> 0)  & 0xFF;
453c19800e8SDoug Rabson   seq[1] = (seq_number >> 8)  & 0xFF;
454c19800e8SDoug Rabson   seq[2] = (seq_number >> 16) & 0xFF;
455c19800e8SDoug Rabson   seq[3] = (seq_number >> 24) & 0xFF;
456c19800e8SDoug Rabson   memset (seq + 4,
457c19800e8SDoug Rabson 	  (ctx->more_flags & LOCAL) ? 0 : 0xFF,
458c19800e8SDoug Rabson 	  4);
459c19800e8SDoug Rabson 
460c19800e8SDoug Rabson 
461c19800e8SDoug Rabson   ret = krb5_crypto_init(context, key, ETYPE_DES3_CBC_NONE,
462c19800e8SDoug Rabson 			 &crypto);
463c19800e8SDoug Rabson   if (ret) {
464c19800e8SDoug Rabson       free (output_message_buffer->value);
465c19800e8SDoug Rabson       output_message_buffer->length = 0;
466c19800e8SDoug Rabson       output_message_buffer->value = NULL;
467c19800e8SDoug Rabson       *minor_status = ret;
468c19800e8SDoug Rabson       return GSS_S_FAILURE;
469c19800e8SDoug Rabson   }
470c19800e8SDoug Rabson 
471c19800e8SDoug Rabson   {
472c19800e8SDoug Rabson       DES_cblock ivec;
473c19800e8SDoug Rabson 
474c19800e8SDoug Rabson       memcpy (&ivec, p + 8, 8);
475c19800e8SDoug Rabson       ret = krb5_encrypt_ivec (context,
476c19800e8SDoug Rabson 			       crypto,
477c19800e8SDoug Rabson 			       KRB5_KU_USAGE_SEQ,
478c19800e8SDoug Rabson 			       seq, 8, &encdata,
479c19800e8SDoug Rabson 			       &ivec);
480c19800e8SDoug Rabson   }
481c19800e8SDoug Rabson   krb5_crypto_destroy (context, crypto);
482c19800e8SDoug Rabson   if (ret) {
483c19800e8SDoug Rabson       free (output_message_buffer->value);
484c19800e8SDoug Rabson       output_message_buffer->length = 0;
485c19800e8SDoug Rabson       output_message_buffer->value = NULL;
486c19800e8SDoug Rabson       *minor_status = ret;
487c19800e8SDoug Rabson       return GSS_S_FAILURE;
488c19800e8SDoug Rabson   }
489c19800e8SDoug Rabson 
490c19800e8SDoug Rabson   assert (encdata.length == 8);
491c19800e8SDoug Rabson 
492c19800e8SDoug Rabson   memcpy (p, encdata.data, encdata.length);
493c19800e8SDoug Rabson   krb5_data_free (&encdata);
494c19800e8SDoug Rabson 
495c19800e8SDoug Rabson   krb5_auth_con_setlocalseqnumber (context,
496c19800e8SDoug Rabson 			       ctx->auth_context,
497c19800e8SDoug Rabson 			       ++seq_number);
498c19800e8SDoug Rabson   HEIMDAL_MUTEX_unlock(&ctx->ctx_id_mutex);
499c19800e8SDoug Rabson 
500c19800e8SDoug Rabson   /* encrypt the data */
501c19800e8SDoug Rabson   p += 28;
502c19800e8SDoug Rabson 
503c19800e8SDoug Rabson   if(conf_req_flag) {
504c19800e8SDoug Rabson       krb5_data tmp;
505c19800e8SDoug Rabson 
506c19800e8SDoug Rabson       ret = krb5_crypto_init(context, key,
507c19800e8SDoug Rabson 			     ETYPE_DES3_CBC_NONE, &crypto);
508c19800e8SDoug Rabson       if (ret) {
509c19800e8SDoug Rabson 	  free (output_message_buffer->value);
510c19800e8SDoug Rabson 	  output_message_buffer->length = 0;
511c19800e8SDoug Rabson 	  output_message_buffer->value = NULL;
512c19800e8SDoug Rabson 	  *minor_status = ret;
513c19800e8SDoug Rabson 	  return GSS_S_FAILURE;
514c19800e8SDoug Rabson       }
515c19800e8SDoug Rabson       ret = krb5_encrypt(context, crypto, KRB5_KU_USAGE_SEAL,
516c19800e8SDoug Rabson 			 p, datalen, &tmp);
517c19800e8SDoug Rabson       krb5_crypto_destroy(context, crypto);
518c19800e8SDoug Rabson       if (ret) {
519c19800e8SDoug Rabson 	  free (output_message_buffer->value);
520c19800e8SDoug Rabson 	  output_message_buffer->length = 0;
521c19800e8SDoug Rabson 	  output_message_buffer->value = NULL;
522c19800e8SDoug Rabson 	  *minor_status = ret;
523c19800e8SDoug Rabson 	  return GSS_S_FAILURE;
524c19800e8SDoug Rabson       }
525c19800e8SDoug Rabson       assert (tmp.length == datalen);
526c19800e8SDoug Rabson 
527c19800e8SDoug Rabson       memcpy (p, tmp.data, datalen);
528c19800e8SDoug Rabson       krb5_data_free(&tmp);
529c19800e8SDoug Rabson   }
530c19800e8SDoug Rabson   if(conf_state != NULL)
531c19800e8SDoug Rabson       *conf_state = conf_req_flag;
532c19800e8SDoug Rabson   *minor_status = 0;
533c19800e8SDoug Rabson   return GSS_S_COMPLETE;
534c19800e8SDoug Rabson }
535c19800e8SDoug Rabson 
536ae771770SStanislav Sedov OM_uint32 GSSAPI_CALLCONV
_gsskrb5_wrap(OM_uint32 * minor_status,const gss_ctx_id_t context_handle,int conf_req_flag,gss_qop_t qop_req,const gss_buffer_t input_message_buffer,int * conf_state,gss_buffer_t output_message_buffer)537ae771770SStanislav Sedov _gsskrb5_wrap
538c19800e8SDoug Rabson            (OM_uint32 * minor_status,
539c19800e8SDoug Rabson             const gss_ctx_id_t context_handle,
540c19800e8SDoug Rabson             int conf_req_flag,
541c19800e8SDoug Rabson             gss_qop_t qop_req,
542c19800e8SDoug Rabson             const gss_buffer_t input_message_buffer,
543c19800e8SDoug Rabson             int * conf_state,
544c19800e8SDoug Rabson             gss_buffer_t output_message_buffer
545c19800e8SDoug Rabson            )
546c19800e8SDoug Rabson {
547c19800e8SDoug Rabson   krb5_context context;
548c19800e8SDoug Rabson   krb5_keyblock *key;
549c19800e8SDoug Rabson   OM_uint32 ret;
550c19800e8SDoug Rabson   krb5_keytype keytype;
551c19800e8SDoug Rabson   const gsskrb5_ctx ctx = (const gsskrb5_ctx) context_handle;
552c19800e8SDoug Rabson 
553ae771770SStanislav Sedov   output_message_buffer->value = NULL;
554ae771770SStanislav Sedov   output_message_buffer->length = 0;
555ae771770SStanislav Sedov 
556c19800e8SDoug Rabson   GSSAPI_KRB5_INIT (&context);
557c19800e8SDoug Rabson 
558ae771770SStanislav Sedov   if (ctx->more_flags & IS_CFX)
559ae771770SStanislav Sedov       return _gssapi_wrap_cfx (minor_status, ctx, context, conf_req_flag,
560ae771770SStanislav Sedov 			       input_message_buffer, conf_state,
561ae771770SStanislav Sedov 			       output_message_buffer);
562ae771770SStanislav Sedov 
563c19800e8SDoug Rabson   HEIMDAL_MUTEX_lock(&ctx->ctx_id_mutex);
564c19800e8SDoug Rabson   ret = _gsskrb5i_get_token_key(ctx, context, &key);
565c19800e8SDoug Rabson   HEIMDAL_MUTEX_unlock(&ctx->ctx_id_mutex);
566c19800e8SDoug Rabson   if (ret) {
567c19800e8SDoug Rabson       *minor_status = ret;
568c19800e8SDoug Rabson       return GSS_S_FAILURE;
569c19800e8SDoug Rabson   }
570c19800e8SDoug Rabson   krb5_enctype_to_keytype (context, key->keytype, &keytype);
571c19800e8SDoug Rabson 
572c19800e8SDoug Rabson   switch (keytype) {
573c19800e8SDoug Rabson   case KEYTYPE_DES :
574ae771770SStanislav Sedov #ifdef HEIM_WEAK_CRYPTO
575c19800e8SDoug Rabson       ret = wrap_des (minor_status, ctx, context, conf_req_flag,
576c19800e8SDoug Rabson 		      qop_req, input_message_buffer, conf_state,
577c19800e8SDoug Rabson 		      output_message_buffer, key);
578ae771770SStanislav Sedov #else
579ae771770SStanislav Sedov       ret = GSS_S_FAILURE;
580ae771770SStanislav Sedov #endif
581c19800e8SDoug Rabson       break;
582c19800e8SDoug Rabson   case KEYTYPE_DES3 :
583c19800e8SDoug Rabson       ret = wrap_des3 (minor_status, ctx, context, conf_req_flag,
584c19800e8SDoug Rabson 		       qop_req, input_message_buffer, conf_state,
585c19800e8SDoug Rabson 		       output_message_buffer, key);
586c19800e8SDoug Rabson       break;
587c19800e8SDoug Rabson   case KEYTYPE_ARCFOUR:
588c19800e8SDoug Rabson   case KEYTYPE_ARCFOUR_56:
589c19800e8SDoug Rabson       ret = _gssapi_wrap_arcfour (minor_status, ctx, context, conf_req_flag,
590c19800e8SDoug Rabson 				  qop_req, input_message_buffer, conf_state,
591c19800e8SDoug Rabson 				  output_message_buffer, key);
592c19800e8SDoug Rabson       break;
593c19800e8SDoug Rabson   default :
594ae771770SStanislav Sedov       abort();
595c19800e8SDoug Rabson       break;
596c19800e8SDoug Rabson   }
597c19800e8SDoug Rabson   krb5_free_keyblock (context, key);
598c19800e8SDoug Rabson   return ret;
599c19800e8SDoug Rabson }
600