xref: /netbsd-src/crypto/external/bsd/heimdal/dist/lib/gssapi/krb5/wrap.c (revision afab4e300d3a9fb07dd8c80daf53d0feb3345706)
1*afab4e30Schristos /*	$NetBSD: wrap.c,v 1.5 2023/06/19 21:41:43 christos Exp $	*/
2ca1c9b0cSelric 
3ca1c9b0cSelric /*
4ca1c9b0cSelric  * Copyright (c) 1997 - 2003 Kungliga Tekniska Högskolan
5ca1c9b0cSelric  * (Royal Institute of Technology, Stockholm, Sweden).
6ca1c9b0cSelric  * All rights reserved.
7ca1c9b0cSelric  *
8ca1c9b0cSelric  * Redistribution and use in source and binary forms, with or without
9ca1c9b0cSelric  * modification, are permitted provided that the following conditions
10ca1c9b0cSelric  * are met:
11ca1c9b0cSelric  *
12ca1c9b0cSelric  * 1. Redistributions of source code must retain the above copyright
13ca1c9b0cSelric  *    notice, this list of conditions and the following disclaimer.
14ca1c9b0cSelric  *
15ca1c9b0cSelric  * 2. Redistributions in binary form must reproduce the above copyright
16ca1c9b0cSelric  *    notice, this list of conditions and the following disclaimer in the
17ca1c9b0cSelric  *    documentation and/or other materials provided with the distribution.
18ca1c9b0cSelric  *
19ca1c9b0cSelric  * 3. Neither the name of the Institute nor the names of its contributors
20ca1c9b0cSelric  *    may be used to endorse or promote products derived from this software
21ca1c9b0cSelric  *    without specific prior written permission.
22ca1c9b0cSelric  *
23ca1c9b0cSelric  * THIS SOFTWARE IS PROVIDED BY THE INSTITUTE AND CONTRIBUTORS ``AS IS'' AND
24ca1c9b0cSelric  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
25ca1c9b0cSelric  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
26ca1c9b0cSelric  * ARE DISCLAIMED.  IN NO EVENT SHALL THE INSTITUTE OR CONTRIBUTORS BE LIABLE
27ca1c9b0cSelric  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
28ca1c9b0cSelric  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
29ca1c9b0cSelric  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
30ca1c9b0cSelric  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
31ca1c9b0cSelric  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
32ca1c9b0cSelric  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
33ca1c9b0cSelric  * SUCH DAMAGE.
34ca1c9b0cSelric  */
35ca1c9b0cSelric 
36ca1c9b0cSelric #include "gsskrb5_locl.h"
37ca1c9b0cSelric 
38ca1c9b0cSelric /*
39ca1c9b0cSelric  * Return initiator subkey, or if that doesn't exists, the subkey.
40ca1c9b0cSelric  */
41ca1c9b0cSelric 
42ca1c9b0cSelric krb5_error_code
_gsskrb5i_get_initiator_subkey(const gsskrb5_ctx ctx,krb5_context context,krb5_keyblock ** key)43ca1c9b0cSelric _gsskrb5i_get_initiator_subkey(const gsskrb5_ctx ctx,
44ca1c9b0cSelric 			       krb5_context context,
45ca1c9b0cSelric 			       krb5_keyblock **key)
46ca1c9b0cSelric {
47ca1c9b0cSelric     krb5_error_code ret;
48ca1c9b0cSelric     *key = NULL;
49ca1c9b0cSelric 
50ca1c9b0cSelric     if (ctx->more_flags & LOCAL) {
51ca1c9b0cSelric 	ret = krb5_auth_con_getlocalsubkey(context,
52ca1c9b0cSelric 				     ctx->auth_context,
53ca1c9b0cSelric 				     key);
54ca1c9b0cSelric     } else {
55ca1c9b0cSelric 	ret = krb5_auth_con_getremotesubkey(context,
56ca1c9b0cSelric 				      ctx->auth_context,
57ca1c9b0cSelric 				      key);
58ca1c9b0cSelric     }
59ca1c9b0cSelric     if (ret == 0 && *key == NULL)
60ca1c9b0cSelric 	ret = krb5_auth_con_getkey(context,
61ca1c9b0cSelric 				   ctx->auth_context,
62ca1c9b0cSelric 				   key);
63ca1c9b0cSelric     if (ret == 0 && *key == NULL) {
64ca1c9b0cSelric 	krb5_set_error_message(context, 0, "No initiator subkey available");
65ca1c9b0cSelric 	return GSS_KRB5_S_KG_NO_SUBKEY;
66ca1c9b0cSelric     }
67ca1c9b0cSelric     return ret;
68ca1c9b0cSelric }
69ca1c9b0cSelric 
70ca1c9b0cSelric krb5_error_code
_gsskrb5i_get_acceptor_subkey(const gsskrb5_ctx ctx,krb5_context context,krb5_keyblock ** key)71ca1c9b0cSelric _gsskrb5i_get_acceptor_subkey(const gsskrb5_ctx ctx,
72ca1c9b0cSelric 			      krb5_context context,
73ca1c9b0cSelric 			      krb5_keyblock **key)
74ca1c9b0cSelric {
75ca1c9b0cSelric     krb5_error_code ret;
76ca1c9b0cSelric     *key = NULL;
77ca1c9b0cSelric 
78ca1c9b0cSelric     if (ctx->more_flags & LOCAL) {
79ca1c9b0cSelric 	ret = krb5_auth_con_getremotesubkey(context,
80ca1c9b0cSelric 				      ctx->auth_context,
81ca1c9b0cSelric 				      key);
82ca1c9b0cSelric     } else {
83ca1c9b0cSelric 	ret = krb5_auth_con_getlocalsubkey(context,
84ca1c9b0cSelric 				     ctx->auth_context,
85ca1c9b0cSelric 				     key);
86ca1c9b0cSelric     }
87ca1c9b0cSelric     if (ret == 0 && *key == NULL) {
88ca1c9b0cSelric 	krb5_set_error_message(context, 0, "No acceptor subkey available");
89ca1c9b0cSelric 	return GSS_KRB5_S_KG_NO_SUBKEY;
90ca1c9b0cSelric     }
91ca1c9b0cSelric     return ret;
92ca1c9b0cSelric }
93ca1c9b0cSelric 
94ca1c9b0cSelric OM_uint32
_gsskrb5i_get_token_key(const gsskrb5_ctx ctx,krb5_context context,krb5_keyblock ** key)95ca1c9b0cSelric _gsskrb5i_get_token_key(const gsskrb5_ctx ctx,
96ca1c9b0cSelric 			krb5_context context,
97ca1c9b0cSelric 			krb5_keyblock **key)
98ca1c9b0cSelric {
99ca1c9b0cSelric     _gsskrb5i_get_acceptor_subkey(ctx, context, key);
100ca1c9b0cSelric     if(*key == NULL) {
101ca1c9b0cSelric 	/*
102ca1c9b0cSelric 	 * Only use the initiator subkey or ticket session key if an
103ca1c9b0cSelric 	 * acceptor subkey was not required.
104ca1c9b0cSelric 	 */
105ca1c9b0cSelric 	if ((ctx->more_flags & ACCEPTOR_SUBKEY) == 0)
106ca1c9b0cSelric 	    _gsskrb5i_get_initiator_subkey(ctx, context, key);
107ca1c9b0cSelric     }
108ca1c9b0cSelric     if (*key == NULL) {
109ca1c9b0cSelric 	krb5_set_error_message(context, 0, "No token key available");
110ca1c9b0cSelric 	return GSS_KRB5_S_KG_NO_SUBKEY;
111ca1c9b0cSelric     }
112ca1c9b0cSelric     return 0;
113ca1c9b0cSelric }
114ca1c9b0cSelric 
115ca1c9b0cSelric static OM_uint32
sub_wrap_size(OM_uint32 req_output_size,OM_uint32 * max_input_size,int blocksize,int extrasize)116ca1c9b0cSelric sub_wrap_size (
117ca1c9b0cSelric             OM_uint32 req_output_size,
118ca1c9b0cSelric             OM_uint32 * max_input_size,
119ca1c9b0cSelric 	    int blocksize,
120ca1c9b0cSelric 	    int extrasize
121ca1c9b0cSelric            )
122ca1c9b0cSelric {
123ca1c9b0cSelric     size_t len, total_len;
124ca1c9b0cSelric 
125ca1c9b0cSelric     len = 8 + req_output_size + blocksize + extrasize;
126ca1c9b0cSelric 
127ca1c9b0cSelric     _gsskrb5_encap_length(len, &len, &total_len, GSS_KRB5_MECHANISM);
128ca1c9b0cSelric 
129ca1c9b0cSelric     total_len -= req_output_size; /* token length */
130ca1c9b0cSelric     if (total_len < req_output_size) {
131ca1c9b0cSelric         *max_input_size = (req_output_size - total_len);
132ca1c9b0cSelric         (*max_input_size) &= (~(OM_uint32)(blocksize - 1));
133ca1c9b0cSelric     } else {
134ca1c9b0cSelric         *max_input_size = 0;
135ca1c9b0cSelric     }
136ca1c9b0cSelric     return GSS_S_COMPLETE;
137ca1c9b0cSelric }
138ca1c9b0cSelric 
139ca1c9b0cSelric OM_uint32 GSSAPI_CALLCONV
_gsskrb5_wrap_size_limit(OM_uint32 * minor_status,gss_const_ctx_id_t context_handle,int conf_req_flag,gss_qop_t qop_req,OM_uint32 req_output_size,OM_uint32 * max_input_size)140ca1c9b0cSelric _gsskrb5_wrap_size_limit (
141ca1c9b0cSelric             OM_uint32 * minor_status,
142b9d004c6Schristos             gss_const_ctx_id_t context_handle,
143ca1c9b0cSelric             int conf_req_flag,
144ca1c9b0cSelric             gss_qop_t qop_req,
145ca1c9b0cSelric             OM_uint32 req_output_size,
146ca1c9b0cSelric             OM_uint32 * max_input_size
147ca1c9b0cSelric            )
148ca1c9b0cSelric {
149ca1c9b0cSelric   krb5_context context;
150ca1c9b0cSelric   krb5_keyblock *key;
151ca1c9b0cSelric   OM_uint32 ret;
152ca1c9b0cSelric   const gsskrb5_ctx ctx = (const gsskrb5_ctx) context_handle;
153ca1c9b0cSelric 
154ca1c9b0cSelric   GSSAPI_KRB5_INIT (&context);
155ca1c9b0cSelric 
156ca1c9b0cSelric   if (ctx->more_flags & IS_CFX)
157ca1c9b0cSelric       return _gssapi_wrap_size_cfx(minor_status, ctx, context,
158ca1c9b0cSelric 				   conf_req_flag, qop_req,
159ca1c9b0cSelric 				   req_output_size, max_input_size);
160ca1c9b0cSelric 
161ca1c9b0cSelric   HEIMDAL_MUTEX_lock(&ctx->ctx_id_mutex);
162ca1c9b0cSelric   ret = _gsskrb5i_get_token_key(ctx, context, &key);
163ca1c9b0cSelric   HEIMDAL_MUTEX_unlock(&ctx->ctx_id_mutex);
164ca1c9b0cSelric   if (ret) {
165ca1c9b0cSelric       *minor_status = ret;
166ca1c9b0cSelric       return GSS_S_FAILURE;
167ca1c9b0cSelric   }
168ca1c9b0cSelric 
169b9d004c6Schristos   switch (key->keytype) {
170b9d004c6Schristos   case KRB5_ENCTYPE_DES_CBC_CRC :
171b9d004c6Schristos   case KRB5_ENCTYPE_DES_CBC_MD4 :
172b9d004c6Schristos   case KRB5_ENCTYPE_DES_CBC_MD5 :
173ca1c9b0cSelric #ifdef HEIM_WEAK_CRYPTO
174ca1c9b0cSelric       ret = sub_wrap_size(req_output_size, max_input_size, 8, 22);
175ca1c9b0cSelric #else
176ca1c9b0cSelric       ret = GSS_S_FAILURE;
177ca1c9b0cSelric #endif
178ca1c9b0cSelric       break;
179b9d004c6Schristos   case KRB5_ENCTYPE_ARCFOUR_HMAC_MD5:
180b9d004c6Schristos   case KRB5_ENCTYPE_ARCFOUR_HMAC_MD5_56:
181ca1c9b0cSelric       ret = _gssapi_wrap_size_arcfour(minor_status, ctx, context,
182ca1c9b0cSelric 				      conf_req_flag, qop_req,
183ca1c9b0cSelric 				      req_output_size, max_input_size, key);
184ca1c9b0cSelric       break;
185b9d004c6Schristos   case KRB5_ENCTYPE_DES3_CBC_MD5 :
186b9d004c6Schristos   case KRB5_ENCTYPE_DES3_CBC_SHA1 :
187ca1c9b0cSelric       ret = sub_wrap_size(req_output_size, max_input_size, 8, 34);
188ca1c9b0cSelric       break;
189ca1c9b0cSelric   default :
190ca1c9b0cSelric       abort();
191ca1c9b0cSelric       break;
192ca1c9b0cSelric   }
193ca1c9b0cSelric   krb5_free_keyblock (context, key);
194ca1c9b0cSelric   *minor_status = 0;
195ca1c9b0cSelric   return ret;
196ca1c9b0cSelric }
197ca1c9b0cSelric 
198ca1c9b0cSelric #ifdef HEIM_WEAK_CRYPTO
199ca1c9b0cSelric 
200ca1c9b0cSelric 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)201ca1c9b0cSelric wrap_des
202ca1c9b0cSelric            (OM_uint32 * minor_status,
203ca1c9b0cSelric             const gsskrb5_ctx ctx,
204ca1c9b0cSelric 	    krb5_context context,
205ca1c9b0cSelric             int conf_req_flag,
206ca1c9b0cSelric             gss_qop_t qop_req,
207ca1c9b0cSelric             const gss_buffer_t input_message_buffer,
208ca1c9b0cSelric             int * conf_state,
209ca1c9b0cSelric             gss_buffer_t output_message_buffer,
210ca1c9b0cSelric 	    krb5_keyblock *key
211ca1c9b0cSelric            )
212ca1c9b0cSelric {
213ca1c9b0cSelric   u_char *p;
214ca1c9b0cSelric   EVP_MD_CTX *md5;
215ca1c9b0cSelric   u_char hash[16];
216ca1c9b0cSelric   DES_key_schedule schedule;
2176680b65dSchristos   EVP_CIPHER_CTX *des_ctx;
218ca1c9b0cSelric   DES_cblock deskey;
219ca1c9b0cSelric   DES_cblock zero;
2204f77a458Spettai   size_t i;
221ca1c9b0cSelric   int32_t seq_number;
222ca1c9b0cSelric   size_t len, total_len, padlength, datalen;
223ca1c9b0cSelric 
224ca1c9b0cSelric   if (IS_DCE_STYLE(ctx)) {
225ca1c9b0cSelric     padlength = 0;
226ca1c9b0cSelric     datalen = input_message_buffer->length;
227ca1c9b0cSelric     len = 22 + 8;
228ca1c9b0cSelric     _gsskrb5_encap_length (len, &len, &total_len, GSS_KRB5_MECHANISM);
229ca1c9b0cSelric     total_len += datalen;
230ca1c9b0cSelric     datalen += 8;
231ca1c9b0cSelric   } else {
232ca1c9b0cSelric     padlength = 8 - (input_message_buffer->length % 8);
233ca1c9b0cSelric     datalen = input_message_buffer->length + padlength + 8;
234ca1c9b0cSelric     len = datalen + 22;
235ca1c9b0cSelric     _gsskrb5_encap_length (len, &len, &total_len, GSS_KRB5_MECHANISM);
236ca1c9b0cSelric   }
237ca1c9b0cSelric 
238ca1c9b0cSelric   output_message_buffer->length = total_len;
239ca1c9b0cSelric   output_message_buffer->value  = malloc (total_len);
240ca1c9b0cSelric   if (output_message_buffer->value == NULL) {
241ca1c9b0cSelric     output_message_buffer->length = 0;
242ca1c9b0cSelric     *minor_status = ENOMEM;
243ca1c9b0cSelric     return GSS_S_FAILURE;
244ca1c9b0cSelric   }
245ca1c9b0cSelric 
246ca1c9b0cSelric   p = _gsskrb5_make_header(output_message_buffer->value,
247ca1c9b0cSelric 			      len,
248ca1c9b0cSelric 			      "\x02\x01", /* TOK_ID */
249ca1c9b0cSelric 			      GSS_KRB5_MECHANISM);
250ca1c9b0cSelric 
251ca1c9b0cSelric   /* SGN_ALG */
252ca1c9b0cSelric   memcpy (p, "\x00\x00", 2);
253ca1c9b0cSelric   p += 2;
254ca1c9b0cSelric   /* SEAL_ALG */
255ca1c9b0cSelric   if(conf_req_flag)
256ca1c9b0cSelric       memcpy (p, "\x00\x00", 2);
257ca1c9b0cSelric   else
258ca1c9b0cSelric       memcpy (p, "\xff\xff", 2);
259ca1c9b0cSelric   p += 2;
260ca1c9b0cSelric   /* Filler */
261ca1c9b0cSelric   memcpy (p, "\xff\xff", 2);
262ca1c9b0cSelric   p += 2;
263ca1c9b0cSelric 
264ca1c9b0cSelric   /* fill in later */
265ca1c9b0cSelric   memset (p, 0, 16);
266ca1c9b0cSelric   p += 16;
267ca1c9b0cSelric 
268ca1c9b0cSelric   /* confounder + data + pad */
269ca1c9b0cSelric   krb5_generate_random_block(p, 8);
270ca1c9b0cSelric   memcpy (p + 8, input_message_buffer->value,
271ca1c9b0cSelric 	  input_message_buffer->length);
272ca1c9b0cSelric   memset (p + 8 + input_message_buffer->length, padlength, padlength);
273ca1c9b0cSelric 
274ca1c9b0cSelric   /* checksum */
275ca1c9b0cSelric   md5 = EVP_MD_CTX_create();
276ca1c9b0cSelric   EVP_DigestInit_ex(md5, EVP_md5(), NULL);
277ca1c9b0cSelric   EVP_DigestUpdate(md5, p - 24, 8);
278ca1c9b0cSelric   EVP_DigestUpdate(md5, p, datalen);
279ca1c9b0cSelric   EVP_DigestFinal_ex(md5, hash, NULL);
280ca1c9b0cSelric   EVP_MD_CTX_destroy(md5);
281ca1c9b0cSelric 
282ca1c9b0cSelric   memset (&zero, 0, sizeof(zero));
283ca1c9b0cSelric   memcpy (&deskey, key->keyvalue.data, sizeof(deskey));
284ca1c9b0cSelric   DES_set_key_unchecked (&deskey, &schedule);
285ca1c9b0cSelric   DES_cbc_cksum ((void *)hash, (void *)hash, sizeof(hash),
286ca1c9b0cSelric 		 &schedule, &zero);
287ca1c9b0cSelric   memcpy (p - 8, hash, 8);
288ca1c9b0cSelric 
289ca1c9b0cSelric   /* sequence number */
290ca1c9b0cSelric   HEIMDAL_MUTEX_lock(&ctx->ctx_id_mutex);
291ca1c9b0cSelric   krb5_auth_con_getlocalseqnumber (context,
292ca1c9b0cSelric 				   ctx->auth_context,
293ca1c9b0cSelric 				   &seq_number);
294ca1c9b0cSelric 
295ca1c9b0cSelric   p -= 16;
296ca1c9b0cSelric   p[0] = (seq_number >> 0)  & 0xFF;
297ca1c9b0cSelric   p[1] = (seq_number >> 8)  & 0xFF;
298ca1c9b0cSelric   p[2] = (seq_number >> 16) & 0xFF;
299ca1c9b0cSelric   p[3] = (seq_number >> 24) & 0xFF;
300ca1c9b0cSelric   memset (p + 4,
301ca1c9b0cSelric 	  (ctx->more_flags & LOCAL) ? 0 : 0xFF,
302ca1c9b0cSelric 	  4);
303ca1c9b0cSelric 
3046680b65dSchristos #if OPENSSL_VERSION_NUMBER < 0x10100000UL
3056680b65dSchristos   EVP_CIPHER_CTX des_ctxs;
3066680b65dSchristos   des_ctx = &des_ctxs;
3076680b65dSchristos   EVP_CIPHER_CTX_init(des_ctx);
3086680b65dSchristos #else
3096680b65dSchristos   des_ctx = EVP_CIPHER_CTX_new();
3106680b65dSchristos #endif
3117b2118deSchristos   if (!EVP_CipherInit_ex(des_ctx, EVP_des_cbc(), NULL, key->keyvalue.data,
3127b2118deSchristos       p + 8, 1)) {
3137b2118deSchristos     *minor_status = EINVAL;
3147b2118deSchristos     return GSS_S_FAILURE;
3157b2118deSchristos   }
3166680b65dSchristos   EVP_Cipher(des_ctx, p, p, 8);
3176680b65dSchristos #if OPENSSL_VERSION_NUMBER < 0x10100000UL
3186680b65dSchristos   EVP_CIPHER_CTX_cleanup(des_ctx);
3196680b65dSchristos #else
3206680b65dSchristos   EVP_CIPHER_CTX_free(des_ctx);
3216680b65dSchristos #endif
322ca1c9b0cSelric 
323ca1c9b0cSelric   krb5_auth_con_setlocalseqnumber (context,
324ca1c9b0cSelric 			       ctx->auth_context,
325ca1c9b0cSelric 			       ++seq_number);
326ca1c9b0cSelric   HEIMDAL_MUTEX_unlock(&ctx->ctx_id_mutex);
327ca1c9b0cSelric 
328ca1c9b0cSelric   /* encrypt the data */
329ca1c9b0cSelric   p += 16;
330ca1c9b0cSelric 
331ca1c9b0cSelric   if(conf_req_flag) {
332ca1c9b0cSelric       memcpy (&deskey, key->keyvalue.data, sizeof(deskey));
333ca1c9b0cSelric 
334ca1c9b0cSelric       for (i = 0; i < sizeof(deskey); ++i)
335ca1c9b0cSelric 	  deskey[i] ^= 0xf0;
336ca1c9b0cSelric 
3376680b65dSchristos #if OPENSSL_VERSION_NUMBER < 0x10100000UL
3386680b65dSchristos       EVP_CIPHER_CTX des_ctxs;
3396680b65dSchristos       des_ctx = &des_ctxs;
3406680b65dSchristos       EVP_CIPHER_CTX_init(des_ctx);
3416680b65dSchristos #else
3426680b65dSchristos       des_ctx = EVP_CIPHER_CTX_new();
3436680b65dSchristos #endif
3447b2118deSchristos       if (!EVP_CipherInit_ex(des_ctx, EVP_des_cbc(), NULL, deskey, zero, 1)) {
3457b2118deSchristos 	*minor_status = EINVAL;
3467b2118deSchristos 	return GSS_S_FAILURE;
3477b2118deSchristos       }
3486680b65dSchristos       EVP_Cipher(des_ctx, p, p, datalen);
3496680b65dSchristos #if OPENSSL_VERSION_NUMBER < 0x10100000UL
3506680b65dSchristos       EVP_CIPHER_CTX_cleanup(des_ctx);
3516680b65dSchristos #else
3526680b65dSchristos       EVP_CIPHER_CTX_free(des_ctx);
3536680b65dSchristos #endif
354ca1c9b0cSelric   }
355ca1c9b0cSelric   memset (deskey, 0, sizeof(deskey));
356ca1c9b0cSelric   memset (&schedule, 0, sizeof(schedule));
357ca1c9b0cSelric 
358ca1c9b0cSelric   if(conf_state != NULL)
359ca1c9b0cSelric       *conf_state = conf_req_flag;
360ca1c9b0cSelric   *minor_status = 0;
361ca1c9b0cSelric   return GSS_S_COMPLETE;
362ca1c9b0cSelric }
363ca1c9b0cSelric 
364ca1c9b0cSelric #endif
365ca1c9b0cSelric 
366ca1c9b0cSelric 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)367ca1c9b0cSelric wrap_des3
368ca1c9b0cSelric            (OM_uint32 * minor_status,
369ca1c9b0cSelric             const gsskrb5_ctx ctx,
370ca1c9b0cSelric 	    krb5_context context,
371ca1c9b0cSelric             int conf_req_flag,
372ca1c9b0cSelric             gss_qop_t qop_req,
373ca1c9b0cSelric             const gss_buffer_t input_message_buffer,
374ca1c9b0cSelric             int * conf_state,
375ca1c9b0cSelric             gss_buffer_t output_message_buffer,
376ca1c9b0cSelric 	    krb5_keyblock *key
377ca1c9b0cSelric            )
378ca1c9b0cSelric {
379ca1c9b0cSelric   u_char *p;
380ca1c9b0cSelric   u_char seq[8];
381ca1c9b0cSelric   int32_t seq_number;
382ca1c9b0cSelric   size_t len, total_len, padlength, datalen;
383ca1c9b0cSelric   uint32_t ret;
384ca1c9b0cSelric   krb5_crypto crypto;
385ca1c9b0cSelric   Checksum cksum;
386ca1c9b0cSelric   krb5_data encdata;
387ca1c9b0cSelric 
388ca1c9b0cSelric   if (IS_DCE_STYLE(ctx)) {
389ca1c9b0cSelric     padlength = 0;
390ca1c9b0cSelric     datalen = input_message_buffer->length;
391ca1c9b0cSelric     len = 34 + 8;
392ca1c9b0cSelric     _gsskrb5_encap_length (len, &len, &total_len, GSS_KRB5_MECHANISM);
393ca1c9b0cSelric     total_len += datalen;
394ca1c9b0cSelric     datalen += 8;
395ca1c9b0cSelric   } else {
396ca1c9b0cSelric     padlength = 8 - (input_message_buffer->length % 8);
397ca1c9b0cSelric     datalen = input_message_buffer->length + padlength + 8;
398ca1c9b0cSelric     len = datalen + 34;
399ca1c9b0cSelric     _gsskrb5_encap_length (len, &len, &total_len, GSS_KRB5_MECHANISM);
400ca1c9b0cSelric   }
401ca1c9b0cSelric 
402ca1c9b0cSelric   output_message_buffer->length = total_len;
403ca1c9b0cSelric   output_message_buffer->value  = malloc (total_len);
404ca1c9b0cSelric   if (output_message_buffer->value == NULL) {
405ca1c9b0cSelric     output_message_buffer->length = 0;
406ca1c9b0cSelric     *minor_status = ENOMEM;
407ca1c9b0cSelric     return GSS_S_FAILURE;
408ca1c9b0cSelric   }
409ca1c9b0cSelric 
410ca1c9b0cSelric   p = _gsskrb5_make_header(output_message_buffer->value,
411ca1c9b0cSelric 			      len,
412ca1c9b0cSelric 			      "\x02\x01", /* TOK_ID */
413ca1c9b0cSelric 			      GSS_KRB5_MECHANISM);
414ca1c9b0cSelric 
415ca1c9b0cSelric   /* SGN_ALG */
416ca1c9b0cSelric   memcpy (p, "\x04\x00", 2);	/* HMAC SHA1 DES3-KD */
417ca1c9b0cSelric   p += 2;
418ca1c9b0cSelric   /* SEAL_ALG */
419ca1c9b0cSelric   if(conf_req_flag)
420ca1c9b0cSelric       memcpy (p, "\x02\x00", 2); /* DES3-KD */
421ca1c9b0cSelric   else
422ca1c9b0cSelric       memcpy (p, "\xff\xff", 2);
423ca1c9b0cSelric   p += 2;
424ca1c9b0cSelric   /* Filler */
425ca1c9b0cSelric   memcpy (p, "\xff\xff", 2);
426ca1c9b0cSelric   p += 2;
427ca1c9b0cSelric 
428ca1c9b0cSelric   /* calculate checksum (the above + confounder + data + pad) */
429ca1c9b0cSelric 
430ca1c9b0cSelric   memcpy (p + 20, p - 8, 8);
431ca1c9b0cSelric   krb5_generate_random_block(p + 28, 8);
432ca1c9b0cSelric   memcpy (p + 28 + 8, input_message_buffer->value,
433ca1c9b0cSelric 	  input_message_buffer->length);
434ca1c9b0cSelric   memset (p + 28 + 8 + input_message_buffer->length, padlength, padlength);
435ca1c9b0cSelric 
436ca1c9b0cSelric   ret = krb5_crypto_init(context, key, 0, &crypto);
437ca1c9b0cSelric   if (ret) {
438ca1c9b0cSelric       free (output_message_buffer->value);
439ca1c9b0cSelric       output_message_buffer->length = 0;
440ca1c9b0cSelric       output_message_buffer->value = NULL;
441ca1c9b0cSelric       *minor_status = ret;
442ca1c9b0cSelric       return GSS_S_FAILURE;
443ca1c9b0cSelric   }
444ca1c9b0cSelric 
445ca1c9b0cSelric   ret = krb5_create_checksum (context,
446ca1c9b0cSelric 			      crypto,
447ca1c9b0cSelric 			      KRB5_KU_USAGE_SIGN,
448ca1c9b0cSelric 			      0,
449ca1c9b0cSelric 			      p + 20,
450ca1c9b0cSelric 			      datalen + 8,
451ca1c9b0cSelric 			      &cksum);
452ca1c9b0cSelric   krb5_crypto_destroy (context, crypto);
453ca1c9b0cSelric   if (ret) {
454ca1c9b0cSelric       free (output_message_buffer->value);
455ca1c9b0cSelric       output_message_buffer->length = 0;
456ca1c9b0cSelric       output_message_buffer->value = NULL;
457ca1c9b0cSelric       *minor_status = ret;
458ca1c9b0cSelric       return GSS_S_FAILURE;
459ca1c9b0cSelric   }
460ca1c9b0cSelric 
461ca1c9b0cSelric   /* zero out SND_SEQ + SGN_CKSUM in case */
462ca1c9b0cSelric   memset (p, 0, 28);
463ca1c9b0cSelric 
464ca1c9b0cSelric   memcpy (p + 8, cksum.checksum.data, cksum.checksum.length);
465ca1c9b0cSelric   free_Checksum (&cksum);
466ca1c9b0cSelric 
467ca1c9b0cSelric   HEIMDAL_MUTEX_lock(&ctx->ctx_id_mutex);
468ca1c9b0cSelric   /* sequence number */
469ca1c9b0cSelric   krb5_auth_con_getlocalseqnumber (context,
470ca1c9b0cSelric 			       ctx->auth_context,
471ca1c9b0cSelric 			       &seq_number);
472ca1c9b0cSelric 
473ca1c9b0cSelric   seq[0] = (seq_number >> 0)  & 0xFF;
474ca1c9b0cSelric   seq[1] = (seq_number >> 8)  & 0xFF;
475ca1c9b0cSelric   seq[2] = (seq_number >> 16) & 0xFF;
476ca1c9b0cSelric   seq[3] = (seq_number >> 24) & 0xFF;
477ca1c9b0cSelric   memset (seq + 4,
478ca1c9b0cSelric 	  (ctx->more_flags & LOCAL) ? 0 : 0xFF,
479ca1c9b0cSelric 	  4);
480ca1c9b0cSelric 
481ca1c9b0cSelric 
482ca1c9b0cSelric   ret = krb5_crypto_init(context, key, ETYPE_DES3_CBC_NONE,
483ca1c9b0cSelric 			 &crypto);
484ca1c9b0cSelric   if (ret) {
485ca1c9b0cSelric       free (output_message_buffer->value);
486ca1c9b0cSelric       output_message_buffer->length = 0;
487ca1c9b0cSelric       output_message_buffer->value = NULL;
488ca1c9b0cSelric       *minor_status = ret;
489ca1c9b0cSelric       return GSS_S_FAILURE;
490ca1c9b0cSelric   }
491ca1c9b0cSelric 
492ca1c9b0cSelric   {
493ca1c9b0cSelric       DES_cblock ivec;
494ca1c9b0cSelric 
495ca1c9b0cSelric       memcpy (&ivec, p + 8, 8);
496ca1c9b0cSelric       ret = krb5_encrypt_ivec (context,
497ca1c9b0cSelric 			       crypto,
498ca1c9b0cSelric 			       KRB5_KU_USAGE_SEQ,
499ca1c9b0cSelric 			       seq, 8, &encdata,
500ca1c9b0cSelric 			       &ivec);
501ca1c9b0cSelric   }
502ca1c9b0cSelric   krb5_crypto_destroy (context, crypto);
503ca1c9b0cSelric   if (ret) {
504ca1c9b0cSelric       free (output_message_buffer->value);
505ca1c9b0cSelric       output_message_buffer->length = 0;
506ca1c9b0cSelric       output_message_buffer->value = NULL;
507ca1c9b0cSelric       *minor_status = ret;
508ca1c9b0cSelric       return GSS_S_FAILURE;
509ca1c9b0cSelric   }
510ca1c9b0cSelric 
511ca1c9b0cSelric   assert (encdata.length == 8);
512ca1c9b0cSelric 
513ca1c9b0cSelric   memcpy (p, encdata.data, encdata.length);
514ca1c9b0cSelric   krb5_data_free (&encdata);
515ca1c9b0cSelric 
516ca1c9b0cSelric   krb5_auth_con_setlocalseqnumber (context,
517ca1c9b0cSelric 			       ctx->auth_context,
518ca1c9b0cSelric 			       ++seq_number);
519ca1c9b0cSelric   HEIMDAL_MUTEX_unlock(&ctx->ctx_id_mutex);
520ca1c9b0cSelric 
521ca1c9b0cSelric   /* encrypt the data */
522ca1c9b0cSelric   p += 28;
523ca1c9b0cSelric 
524ca1c9b0cSelric   if(conf_req_flag) {
525ca1c9b0cSelric       krb5_data tmp;
526ca1c9b0cSelric 
527ca1c9b0cSelric       ret = krb5_crypto_init(context, key,
528ca1c9b0cSelric 			     ETYPE_DES3_CBC_NONE, &crypto);
529ca1c9b0cSelric       if (ret) {
530ca1c9b0cSelric 	  free (output_message_buffer->value);
531ca1c9b0cSelric 	  output_message_buffer->length = 0;
532ca1c9b0cSelric 	  output_message_buffer->value = NULL;
533ca1c9b0cSelric 	  *minor_status = ret;
534ca1c9b0cSelric 	  return GSS_S_FAILURE;
535ca1c9b0cSelric       }
536ca1c9b0cSelric       ret = krb5_encrypt(context, crypto, KRB5_KU_USAGE_SEAL,
537ca1c9b0cSelric 			 p, datalen, &tmp);
538ca1c9b0cSelric       krb5_crypto_destroy(context, crypto);
539ca1c9b0cSelric       if (ret) {
540ca1c9b0cSelric 	  free (output_message_buffer->value);
541ca1c9b0cSelric 	  output_message_buffer->length = 0;
542ca1c9b0cSelric 	  output_message_buffer->value = NULL;
543ca1c9b0cSelric 	  *minor_status = ret;
544ca1c9b0cSelric 	  return GSS_S_FAILURE;
545ca1c9b0cSelric       }
546ca1c9b0cSelric       assert (tmp.length == datalen);
547ca1c9b0cSelric 
548ca1c9b0cSelric       memcpy (p, tmp.data, datalen);
549ca1c9b0cSelric       krb5_data_free(&tmp);
550ca1c9b0cSelric   }
551ca1c9b0cSelric   if(conf_state != NULL)
552ca1c9b0cSelric       *conf_state = conf_req_flag;
553ca1c9b0cSelric   *minor_status = 0;
554ca1c9b0cSelric   return GSS_S_COMPLETE;
555ca1c9b0cSelric }
556ca1c9b0cSelric 
557ca1c9b0cSelric OM_uint32 GSSAPI_CALLCONV
_gsskrb5_wrap(OM_uint32 * minor_status,gss_const_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)558ca1c9b0cSelric _gsskrb5_wrap
559ca1c9b0cSelric            (OM_uint32 * minor_status,
560b9d004c6Schristos             gss_const_ctx_id_t context_handle,
561ca1c9b0cSelric             int conf_req_flag,
562ca1c9b0cSelric             gss_qop_t qop_req,
563ca1c9b0cSelric             const gss_buffer_t input_message_buffer,
564ca1c9b0cSelric             int * conf_state,
565ca1c9b0cSelric             gss_buffer_t output_message_buffer
566ca1c9b0cSelric            )
567ca1c9b0cSelric {
568ca1c9b0cSelric   krb5_context context;
569ca1c9b0cSelric   krb5_keyblock *key;
570ca1c9b0cSelric   OM_uint32 ret;
571ca1c9b0cSelric   const gsskrb5_ctx ctx = (const gsskrb5_ctx) context_handle;
572ca1c9b0cSelric 
573ca1c9b0cSelric   output_message_buffer->value = NULL;
574ca1c9b0cSelric   output_message_buffer->length = 0;
575ca1c9b0cSelric 
576ca1c9b0cSelric   GSSAPI_KRB5_INIT (&context);
577ca1c9b0cSelric 
578ca1c9b0cSelric   if (ctx->more_flags & IS_CFX)
579ca1c9b0cSelric       return _gssapi_wrap_cfx (minor_status, ctx, context, conf_req_flag,
580ca1c9b0cSelric 			       input_message_buffer, conf_state,
581ca1c9b0cSelric 			       output_message_buffer);
582ca1c9b0cSelric 
583ca1c9b0cSelric   HEIMDAL_MUTEX_lock(&ctx->ctx_id_mutex);
584ca1c9b0cSelric   ret = _gsskrb5i_get_token_key(ctx, context, &key);
585ca1c9b0cSelric   HEIMDAL_MUTEX_unlock(&ctx->ctx_id_mutex);
586ca1c9b0cSelric   if (ret) {
587ca1c9b0cSelric       *minor_status = ret;
588ca1c9b0cSelric       return GSS_S_FAILURE;
589ca1c9b0cSelric   }
590ca1c9b0cSelric 
591b9d004c6Schristos   switch (key->keytype) {
592b9d004c6Schristos   case KRB5_ENCTYPE_DES_CBC_CRC :
593b9d004c6Schristos   case KRB5_ENCTYPE_DES_CBC_MD4 :
594b9d004c6Schristos   case KRB5_ENCTYPE_DES_CBC_MD5 :
595ca1c9b0cSelric #ifdef HEIM_WEAK_CRYPTO
596ca1c9b0cSelric       ret = wrap_des (minor_status, ctx, context, conf_req_flag,
597ca1c9b0cSelric 		      qop_req, input_message_buffer, conf_state,
598ca1c9b0cSelric 		      output_message_buffer, key);
599ca1c9b0cSelric #else
600ca1c9b0cSelric       ret = GSS_S_FAILURE;
601ca1c9b0cSelric #endif
602ca1c9b0cSelric       break;
603b9d004c6Schristos   case KRB5_ENCTYPE_DES3_CBC_MD5 :
604b9d004c6Schristos   case KRB5_ENCTYPE_DES3_CBC_SHA1 :
605ca1c9b0cSelric       ret = wrap_des3 (minor_status, ctx, context, conf_req_flag,
606ca1c9b0cSelric 		       qop_req, input_message_buffer, conf_state,
607ca1c9b0cSelric 		       output_message_buffer, key);
608ca1c9b0cSelric       break;
609b9d004c6Schristos   case KRB5_ENCTYPE_ARCFOUR_HMAC_MD5:
610b9d004c6Schristos   case KRB5_ENCTYPE_ARCFOUR_HMAC_MD5_56:
611ca1c9b0cSelric       ret = _gssapi_wrap_arcfour (minor_status, ctx, context, conf_req_flag,
612ca1c9b0cSelric 				  qop_req, input_message_buffer, conf_state,
613ca1c9b0cSelric 				  output_message_buffer, key);
614ca1c9b0cSelric       break;
615ca1c9b0cSelric   default :
616ca1c9b0cSelric       abort();
617ca1c9b0cSelric       break;
618ca1c9b0cSelric   }
619ca1c9b0cSelric   krb5_free_keyblock (context, key);
620ca1c9b0cSelric   return ret;
621ca1c9b0cSelric }
622