xref: /freebsd/crypto/heimdal/lib/gssapi/krb5/unwrap.c (revision ed549cb0c53f8438c52593ce811f6fcc812248e9)
1c19800e8SDoug Rabson /*
2ae771770SStanislav Sedov  * Copyright (c) 1997 - 2004 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 
36ae771770SStanislav Sedov #ifdef HEIM_WEAK_CRYPTO
37c19800e8SDoug Rabson 
38c19800e8SDoug Rabson static OM_uint32
unwrap_des(OM_uint32 * minor_status,const gsskrb5_ctx context_handle,const gss_buffer_t input_message_buffer,gss_buffer_t output_message_buffer,int * conf_state,gss_qop_t * qop_state,krb5_keyblock * key)39c19800e8SDoug Rabson unwrap_des
40c19800e8SDoug Rabson            (OM_uint32 * minor_status,
41c19800e8SDoug Rabson             const gsskrb5_ctx context_handle,
42c19800e8SDoug Rabson             const gss_buffer_t input_message_buffer,
43c19800e8SDoug Rabson             gss_buffer_t output_message_buffer,
44c19800e8SDoug Rabson             int * conf_state,
45c19800e8SDoug Rabson             gss_qop_t * qop_state,
46c19800e8SDoug Rabson 	    krb5_keyblock *key
47c19800e8SDoug Rabson            )
48c19800e8SDoug Rabson {
49c19800e8SDoug Rabson   u_char *p, *seq;
50c19800e8SDoug Rabson   size_t len;
51ae771770SStanislav Sedov   EVP_MD_CTX *md5;
52c19800e8SDoug Rabson   u_char hash[16];
53e4456411SJohn Baldwin   EVP_CIPHER_CTX *des_ctx;
54c19800e8SDoug Rabson   DES_key_schedule schedule;
55c19800e8SDoug Rabson   DES_cblock deskey;
56c19800e8SDoug Rabson   DES_cblock zero;
57ae771770SStanislav Sedov   size_t i;
58c19800e8SDoug Rabson   uint32_t seq_number;
59c19800e8SDoug Rabson   size_t padlength;
60c19800e8SDoug Rabson   OM_uint32 ret;
61c19800e8SDoug Rabson   int cstate;
62c19800e8SDoug Rabson   int cmp;
63ae771770SStanislav Sedov   int token_len;
64ae771770SStanislav Sedov 
65ae771770SStanislav Sedov   if (IS_DCE_STYLE(context_handle)) {
66ae771770SStanislav Sedov      token_len = 22 + 8 + 15; /* 45 */
67*ed549cb0SCy Schubert      if (input_message_buffer->length < token_len)
68*ed549cb0SCy Schubert 	  return GSS_S_BAD_MECH;
69ae771770SStanislav Sedov   } else {
70ae771770SStanislav Sedov      token_len = input_message_buffer->length;
71ae771770SStanislav Sedov   }
72c19800e8SDoug Rabson 
73c19800e8SDoug Rabson   p = input_message_buffer->value;
74c19800e8SDoug Rabson   ret = _gsskrb5_verify_header (&p,
75ae771770SStanislav Sedov 				   token_len,
76c19800e8SDoug Rabson 				   "\x02\x01",
77c19800e8SDoug Rabson 				   GSS_KRB5_MECHANISM);
78c19800e8SDoug Rabson   if (ret)
79c19800e8SDoug Rabson       return ret;
80c19800e8SDoug Rabson 
81*ed549cb0SCy Schubert   len = (p - (u_char *)input_message_buffer->value)
82*ed549cb0SCy Schubert       + 22 + 8;
83*ed549cb0SCy Schubert   if (input_message_buffer->length < len)
84*ed549cb0SCy Schubert       return GSS_S_BAD_MECH;
85*ed549cb0SCy Schubert 
86c19800e8SDoug Rabson   if (memcmp (p, "\x00\x00", 2) != 0)
87c19800e8SDoug Rabson     return GSS_S_BAD_SIG;
88c19800e8SDoug Rabson   p += 2;
89c19800e8SDoug Rabson   if (memcmp (p, "\x00\x00", 2) == 0) {
90c19800e8SDoug Rabson       cstate = 1;
91c19800e8SDoug Rabson   } else if (memcmp (p, "\xFF\xFF", 2) == 0) {
92c19800e8SDoug Rabson       cstate = 0;
93c19800e8SDoug Rabson   } else
94c19800e8SDoug Rabson       return GSS_S_BAD_MIC;
95c19800e8SDoug Rabson   p += 2;
96c19800e8SDoug Rabson   if(conf_state != NULL)
97c19800e8SDoug Rabson       *conf_state = cstate;
98c19800e8SDoug Rabson   if (memcmp (p, "\xff\xff", 2) != 0)
99c19800e8SDoug Rabson     return GSS_S_DEFECTIVE_TOKEN;
100c19800e8SDoug Rabson   p += 2;
101c19800e8SDoug Rabson   p += 16;
102c19800e8SDoug Rabson 
103c19800e8SDoug Rabson   len = p - (u_char *)input_message_buffer->value;
104c19800e8SDoug Rabson 
105c19800e8SDoug Rabson   if(cstate) {
106c19800e8SDoug Rabson       /* decrypt data */
107c19800e8SDoug Rabson       memcpy (&deskey, key->keyvalue.data, sizeof(deskey));
108ae771770SStanislav Sedov       memset (&zero, 0, sizeof(zero));
109c19800e8SDoug Rabson 
110c19800e8SDoug Rabson       for (i = 0; i < sizeof(deskey); ++i)
111c19800e8SDoug Rabson 	  deskey[i] ^= 0xf0;
112c19800e8SDoug Rabson 
113ae771770SStanislav Sedov 
114e4456411SJohn Baldwin       des_ctx = EVP_CIPHER_CTX_new();
115e4456411SJohn Baldwin       if (des_ctx == NULL) {
116e4456411SJohn Baldwin 	  memset (deskey, 0, sizeof(deskey));
117e4456411SJohn Baldwin 	  *minor_status = ENOMEM;
118e4456411SJohn Baldwin 	  return GSS_S_FAILURE;
119e4456411SJohn Baldwin       }
120e4456411SJohn Baldwin       EVP_CipherInit_ex(des_ctx, EVP_des_cbc(), NULL, deskey, zero, 0);
121e4456411SJohn Baldwin       EVP_Cipher(des_ctx, p, p, input_message_buffer->length - len);
122e4456411SJohn Baldwin       EVP_CIPHER_CTX_free(des_ctx);
123ae771770SStanislav Sedov 
124e4456411SJohn Baldwin       memset (deskey, 0, sizeof(deskey));
125c19800e8SDoug Rabson   }
126ae771770SStanislav Sedov 
127ae771770SStanislav Sedov   if (IS_DCE_STYLE(context_handle)) {
128ae771770SStanislav Sedov     padlength = 0;
129ae771770SStanislav Sedov   } else {
130c19800e8SDoug Rabson     /* check pad */
131c19800e8SDoug Rabson     ret = _gssapi_verify_pad(input_message_buffer,
132*ed549cb0SCy Schubert 			     input_message_buffer->length - len - 8,
133c19800e8SDoug Rabson 			     &padlength);
134c19800e8SDoug Rabson     if (ret)
135c19800e8SDoug Rabson         return ret;
136ae771770SStanislav Sedov   }
137c19800e8SDoug Rabson 
138ae771770SStanislav Sedov   md5 = EVP_MD_CTX_create();
139ae771770SStanislav Sedov   EVP_DigestInit_ex(md5, EVP_md5(), NULL);
140ae771770SStanislav Sedov   EVP_DigestUpdate(md5, p - 24, 8);
141ae771770SStanislav Sedov   EVP_DigestUpdate(md5, p, input_message_buffer->length - len);
142ae771770SStanislav Sedov   EVP_DigestFinal_ex(md5, hash, NULL);
143ae771770SStanislav Sedov   EVP_MD_CTX_destroy(md5);
144c19800e8SDoug Rabson 
145c19800e8SDoug Rabson   memset (&zero, 0, sizeof(zero));
146c19800e8SDoug Rabson   memcpy (&deskey, key->keyvalue.data, sizeof(deskey));
147ae771770SStanislav Sedov   DES_set_key_unchecked (&deskey, &schedule);
148c19800e8SDoug Rabson   DES_cbc_cksum ((void *)hash, (void *)hash, sizeof(hash),
149c19800e8SDoug Rabson 		 &schedule, &zero);
150e4456411SJohn Baldwin   if (ct_memcmp (p - 8, hash, 8) != 0) {
151e4456411SJohn Baldwin     memset (deskey, 0, sizeof(deskey));
152e4456411SJohn Baldwin     memset (&schedule, 0, sizeof(schedule));
153c19800e8SDoug Rabson     return GSS_S_BAD_MIC;
154e4456411SJohn Baldwin   }
155c19800e8SDoug Rabson 
156c19800e8SDoug Rabson   /* verify sequence number */
157c19800e8SDoug Rabson 
158e4456411SJohn Baldwin   des_ctx = EVP_CIPHER_CTX_new();
159e4456411SJohn Baldwin   if (des_ctx == NULL) {
160e4456411SJohn Baldwin     memset (deskey, 0, sizeof(deskey));
161e4456411SJohn Baldwin     memset (&schedule, 0, sizeof(schedule));
162e4456411SJohn Baldwin     *minor_status = ENOMEM;
163e4456411SJohn Baldwin     return GSS_S_FAILURE;
164e4456411SJohn Baldwin   }
165e4456411SJohn Baldwin 
166c19800e8SDoug Rabson   HEIMDAL_MUTEX_lock(&context_handle->ctx_id_mutex);
167c19800e8SDoug Rabson 
168c19800e8SDoug Rabson   p -= 16;
169ae771770SStanislav Sedov 
170e4456411SJohn Baldwin   EVP_CipherInit_ex(des_ctx, EVP_des_cbc(), NULL, key->keyvalue.data, hash, 0);
171e4456411SJohn Baldwin   EVP_Cipher(des_ctx, p, p, 8);
172e4456411SJohn Baldwin   EVP_CIPHER_CTX_free(des_ctx);
173c19800e8SDoug Rabson 
174c19800e8SDoug Rabson   memset (deskey, 0, sizeof(deskey));
175c19800e8SDoug Rabson   memset (&schedule, 0, sizeof(schedule));
176c19800e8SDoug Rabson 
177c19800e8SDoug Rabson   seq = p;
178c19800e8SDoug Rabson   _gsskrb5_decode_om_uint32(seq, &seq_number);
179c19800e8SDoug Rabson 
180c19800e8SDoug Rabson   if (context_handle->more_flags & LOCAL)
181ae771770SStanislav Sedov       cmp = ct_memcmp(&seq[4], "\xff\xff\xff\xff", 4);
182c19800e8SDoug Rabson   else
183ae771770SStanislav Sedov       cmp = ct_memcmp(&seq[4], "\x00\x00\x00\x00", 4);
184c19800e8SDoug Rabson 
185c19800e8SDoug Rabson   if (cmp != 0) {
186c19800e8SDoug Rabson     HEIMDAL_MUTEX_unlock(&context_handle->ctx_id_mutex);
187c19800e8SDoug Rabson     return GSS_S_BAD_MIC;
188c19800e8SDoug Rabson   }
189c19800e8SDoug Rabson 
190c19800e8SDoug Rabson   ret = _gssapi_msg_order_check(context_handle->order, seq_number);
191c19800e8SDoug Rabson   if (ret) {
192c19800e8SDoug Rabson     HEIMDAL_MUTEX_unlock(&context_handle->ctx_id_mutex);
193c19800e8SDoug Rabson     return ret;
194c19800e8SDoug Rabson   }
195c19800e8SDoug Rabson 
196c19800e8SDoug Rabson   HEIMDAL_MUTEX_unlock(&context_handle->ctx_id_mutex);
197c19800e8SDoug Rabson 
198c19800e8SDoug Rabson   /* copy out data */
199c19800e8SDoug Rabson 
200c19800e8SDoug Rabson   output_message_buffer->length = input_message_buffer->length
201c19800e8SDoug Rabson     - len - padlength - 8;
202c19800e8SDoug Rabson   output_message_buffer->value  = malloc(output_message_buffer->length);
203c19800e8SDoug Rabson   if(output_message_buffer->length != 0 && output_message_buffer->value == NULL)
204c19800e8SDoug Rabson       return GSS_S_FAILURE;
205*ed549cb0SCy Schubert   if (output_message_buffer->value != NULL)
206c19800e8SDoug Rabson       memcpy (output_message_buffer->value,
207c19800e8SDoug Rabson 	      p + 24,
208c19800e8SDoug Rabson 	      output_message_buffer->length);
209c19800e8SDoug Rabson   return GSS_S_COMPLETE;
210c19800e8SDoug Rabson }
211ae771770SStanislav Sedov #endif
212c19800e8SDoug Rabson 
213c19800e8SDoug Rabson static OM_uint32
unwrap_des3(OM_uint32 * minor_status,const gsskrb5_ctx context_handle,krb5_context context,const gss_buffer_t input_message_buffer,gss_buffer_t output_message_buffer,int * conf_state,gss_qop_t * qop_state,krb5_keyblock * key)214c19800e8SDoug Rabson unwrap_des3
215c19800e8SDoug Rabson            (OM_uint32 * minor_status,
216c19800e8SDoug Rabson             const gsskrb5_ctx context_handle,
217c19800e8SDoug Rabson 	    krb5_context context,
218c19800e8SDoug Rabson             const gss_buffer_t input_message_buffer,
219c19800e8SDoug Rabson             gss_buffer_t output_message_buffer,
220c19800e8SDoug Rabson             int * conf_state,
221c19800e8SDoug Rabson             gss_qop_t * qop_state,
222c19800e8SDoug Rabson 	    krb5_keyblock *key
223c19800e8SDoug Rabson            )
224c19800e8SDoug Rabson {
225c19800e8SDoug Rabson   u_char *p;
226c19800e8SDoug Rabson   size_t len;
227c19800e8SDoug Rabson   u_char *seq;
228c19800e8SDoug Rabson   krb5_data seq_data;
229c19800e8SDoug Rabson   u_char cksum[20];
230c19800e8SDoug Rabson   uint32_t seq_number;
231c19800e8SDoug Rabson   size_t padlength;
232c19800e8SDoug Rabson   OM_uint32 ret;
233c19800e8SDoug Rabson   int cstate;
234c19800e8SDoug Rabson   krb5_crypto crypto;
235c19800e8SDoug Rabson   Checksum csum;
236c19800e8SDoug Rabson   int cmp;
237ae771770SStanislav Sedov   int token_len;
238ae771770SStanislav Sedov 
239ae771770SStanislav Sedov   if (IS_DCE_STYLE(context_handle)) {
240ae771770SStanislav Sedov      token_len = 34 + 8 + 15; /* 57 */
241*ed549cb0SCy Schubert      if (input_message_buffer->length < token_len)
242*ed549cb0SCy Schubert 	  return GSS_S_BAD_MECH;
243ae771770SStanislav Sedov   } else {
244ae771770SStanislav Sedov      token_len = input_message_buffer->length;
245ae771770SStanislav Sedov   }
246c19800e8SDoug Rabson 
247c19800e8SDoug Rabson   p = input_message_buffer->value;
248c19800e8SDoug Rabson   ret = _gsskrb5_verify_header (&p,
249ae771770SStanislav Sedov 				   token_len,
250c19800e8SDoug Rabson 				   "\x02\x01",
251c19800e8SDoug Rabson 				   GSS_KRB5_MECHANISM);
252c19800e8SDoug Rabson   if (ret)
253c19800e8SDoug Rabson       return ret;
254c19800e8SDoug Rabson 
255*ed549cb0SCy Schubert   len = (p - (u_char *)input_message_buffer->value)
256*ed549cb0SCy Schubert       + 34 + 8;
257*ed549cb0SCy Schubert   if (input_message_buffer->length < len)
258*ed549cb0SCy Schubert       return GSS_S_BAD_MECH;
259*ed549cb0SCy Schubert 
260*ed549cb0SCy Schubert   if (ct_memcmp (p, "\x04\x00", 2) != 0) /* HMAC SHA1 DES3_KD */
261c19800e8SDoug Rabson     return GSS_S_BAD_SIG;
262c19800e8SDoug Rabson   p += 2;
263ae771770SStanislav Sedov   if (ct_memcmp (p, "\x02\x00", 2) == 0) {
264c19800e8SDoug Rabson     cstate = 1;
265ae771770SStanislav Sedov   } else if (ct_memcmp (p, "\xff\xff", 2) == 0) {
266c19800e8SDoug Rabson     cstate = 0;
267c19800e8SDoug Rabson   } else
268c19800e8SDoug Rabson     return GSS_S_BAD_MIC;
269c19800e8SDoug Rabson   p += 2;
270c19800e8SDoug Rabson   if(conf_state != NULL)
271c19800e8SDoug Rabson     *conf_state = cstate;
272ae771770SStanislav Sedov   if (ct_memcmp (p, "\xff\xff", 2) != 0)
273c19800e8SDoug Rabson     return GSS_S_DEFECTIVE_TOKEN;
274c19800e8SDoug Rabson   p += 2;
275c19800e8SDoug Rabson   p += 28;
276c19800e8SDoug Rabson 
277c19800e8SDoug Rabson   len = p - (u_char *)input_message_buffer->value;
278c19800e8SDoug Rabson 
279c19800e8SDoug Rabson   if(cstate) {
280c19800e8SDoug Rabson       /* decrypt data */
281c19800e8SDoug Rabson       krb5_data tmp;
282c19800e8SDoug Rabson 
283c19800e8SDoug Rabson       ret = krb5_crypto_init(context, key,
284c19800e8SDoug Rabson 			     ETYPE_DES3_CBC_NONE, &crypto);
285c19800e8SDoug Rabson       if (ret) {
286c19800e8SDoug Rabson 	  *minor_status = ret;
287c19800e8SDoug Rabson 	  return GSS_S_FAILURE;
288c19800e8SDoug Rabson       }
289c19800e8SDoug Rabson       ret = krb5_decrypt(context, crypto, KRB5_KU_USAGE_SEAL,
290c19800e8SDoug Rabson 			 p, input_message_buffer->length - len, &tmp);
291c19800e8SDoug Rabson       krb5_crypto_destroy(context, crypto);
292c19800e8SDoug Rabson       if (ret) {
293c19800e8SDoug Rabson 	  *minor_status = ret;
294c19800e8SDoug Rabson 	  return GSS_S_FAILURE;
295c19800e8SDoug Rabson       }
296c19800e8SDoug Rabson       assert (tmp.length == input_message_buffer->length - len);
297c19800e8SDoug Rabson 
298c19800e8SDoug Rabson       memcpy (p, tmp.data, tmp.length);
299c19800e8SDoug Rabson       krb5_data_free(&tmp);
300c19800e8SDoug Rabson   }
301ae771770SStanislav Sedov 
302ae771770SStanislav Sedov   if (IS_DCE_STYLE(context_handle)) {
303ae771770SStanislav Sedov     padlength = 0;
304ae771770SStanislav Sedov   } else {
305c19800e8SDoug Rabson     /* check pad */
306c19800e8SDoug Rabson     ret = _gssapi_verify_pad(input_message_buffer,
307*ed549cb0SCy Schubert 			     input_message_buffer->length - len - 8,
308c19800e8SDoug Rabson 			     &padlength);
309c19800e8SDoug Rabson     if (ret)
310c19800e8SDoug Rabson         return ret;
311ae771770SStanislav Sedov   }
312c19800e8SDoug Rabson 
313c19800e8SDoug Rabson   /* verify sequence number */
314c19800e8SDoug Rabson 
315c19800e8SDoug Rabson   HEIMDAL_MUTEX_lock(&context_handle->ctx_id_mutex);
316c19800e8SDoug Rabson 
317c19800e8SDoug Rabson   p -= 28;
318c19800e8SDoug Rabson 
319c19800e8SDoug Rabson   ret = krb5_crypto_init(context, key,
320c19800e8SDoug Rabson 			 ETYPE_DES3_CBC_NONE, &crypto);
321c19800e8SDoug Rabson   if (ret) {
322c19800e8SDoug Rabson       *minor_status = ret;
323c19800e8SDoug Rabson       HEIMDAL_MUTEX_unlock(&context_handle->ctx_id_mutex);
324c19800e8SDoug Rabson       return GSS_S_FAILURE;
325c19800e8SDoug Rabson   }
326c19800e8SDoug Rabson   {
327c19800e8SDoug Rabson       DES_cblock ivec;
328c19800e8SDoug Rabson 
329c19800e8SDoug Rabson       memcpy(&ivec, p + 8, 8);
330c19800e8SDoug Rabson       ret = krb5_decrypt_ivec (context,
331c19800e8SDoug Rabson 			       crypto,
332c19800e8SDoug Rabson 			       KRB5_KU_USAGE_SEQ,
333c19800e8SDoug Rabson 			       p, 8, &seq_data,
334c19800e8SDoug Rabson 			       &ivec);
335c19800e8SDoug Rabson   }
336c19800e8SDoug Rabson   krb5_crypto_destroy (context, crypto);
337c19800e8SDoug Rabson   if (ret) {
338c19800e8SDoug Rabson       *minor_status = ret;
339c19800e8SDoug Rabson       HEIMDAL_MUTEX_unlock(&context_handle->ctx_id_mutex);
340c19800e8SDoug Rabson       return GSS_S_FAILURE;
341c19800e8SDoug Rabson   }
342c19800e8SDoug Rabson   if (seq_data.length != 8) {
343c19800e8SDoug Rabson       krb5_data_free (&seq_data);
344c19800e8SDoug Rabson       *minor_status = 0;
345c19800e8SDoug Rabson       HEIMDAL_MUTEX_unlock(&context_handle->ctx_id_mutex);
346c19800e8SDoug Rabson       return GSS_S_BAD_MIC;
347c19800e8SDoug Rabson   }
348c19800e8SDoug Rabson 
349c19800e8SDoug Rabson   seq = seq_data.data;
350c19800e8SDoug Rabson   _gsskrb5_decode_om_uint32(seq, &seq_number);
351c19800e8SDoug Rabson 
352c19800e8SDoug Rabson   if (context_handle->more_flags & LOCAL)
353ae771770SStanislav Sedov       cmp = ct_memcmp(&seq[4], "\xff\xff\xff\xff", 4);
354c19800e8SDoug Rabson   else
355ae771770SStanislav Sedov       cmp = ct_memcmp(&seq[4], "\x00\x00\x00\x00", 4);
356c19800e8SDoug Rabson 
357c19800e8SDoug Rabson   krb5_data_free (&seq_data);
358c19800e8SDoug Rabson   if (cmp != 0) {
359c19800e8SDoug Rabson       *minor_status = 0;
360c19800e8SDoug Rabson       HEIMDAL_MUTEX_unlock(&context_handle->ctx_id_mutex);
361c19800e8SDoug Rabson       return GSS_S_BAD_MIC;
362c19800e8SDoug Rabson   }
363c19800e8SDoug Rabson 
364c19800e8SDoug Rabson   ret = _gssapi_msg_order_check(context_handle->order, seq_number);
365c19800e8SDoug Rabson   if (ret) {
366c19800e8SDoug Rabson       *minor_status = 0;
367c19800e8SDoug Rabson       HEIMDAL_MUTEX_unlock(&context_handle->ctx_id_mutex);
368c19800e8SDoug Rabson       return ret;
369c19800e8SDoug Rabson   }
370c19800e8SDoug Rabson 
371c19800e8SDoug Rabson   HEIMDAL_MUTEX_unlock(&context_handle->ctx_id_mutex);
372c19800e8SDoug Rabson 
373c19800e8SDoug Rabson   /* verify checksum */
374c19800e8SDoug Rabson 
375c19800e8SDoug Rabson   memcpy (cksum, p + 8, 20);
376c19800e8SDoug Rabson 
377c19800e8SDoug Rabson   memcpy (p + 20, p - 8, 8);
378c19800e8SDoug Rabson 
379c19800e8SDoug Rabson   csum.cksumtype = CKSUMTYPE_HMAC_SHA1_DES3;
380c19800e8SDoug Rabson   csum.checksum.length = 20;
381c19800e8SDoug Rabson   csum.checksum.data   = cksum;
382c19800e8SDoug Rabson 
383c19800e8SDoug Rabson   ret = krb5_crypto_init(context, key, 0, &crypto);
384c19800e8SDoug Rabson   if (ret) {
385c19800e8SDoug Rabson       *minor_status = ret;
386c19800e8SDoug Rabson       return GSS_S_FAILURE;
387c19800e8SDoug Rabson   }
388c19800e8SDoug Rabson 
389c19800e8SDoug Rabson   ret = krb5_verify_checksum (context, crypto,
390c19800e8SDoug Rabson 			      KRB5_KU_USAGE_SIGN,
391c19800e8SDoug Rabson 			      p + 20,
392c19800e8SDoug Rabson 			      input_message_buffer->length - len + 8,
393c19800e8SDoug Rabson 			      &csum);
394c19800e8SDoug Rabson   krb5_crypto_destroy (context, crypto);
395c19800e8SDoug Rabson   if (ret) {
396c19800e8SDoug Rabson       *minor_status = ret;
397c19800e8SDoug Rabson       return GSS_S_FAILURE;
398c19800e8SDoug Rabson   }
399c19800e8SDoug Rabson 
400c19800e8SDoug Rabson   /* copy out data */
401c19800e8SDoug Rabson 
402c19800e8SDoug Rabson   output_message_buffer->length = input_message_buffer->length
403c19800e8SDoug Rabson     - len - padlength - 8;
404c19800e8SDoug Rabson   output_message_buffer->value  = malloc(output_message_buffer->length);
405c19800e8SDoug Rabson   if(output_message_buffer->length != 0 && output_message_buffer->value == NULL)
406c19800e8SDoug Rabson       return GSS_S_FAILURE;
407*ed549cb0SCy Schubert   if (output_message_buffer->value != NULL)
408c19800e8SDoug Rabson       memcpy (output_message_buffer->value,
409c19800e8SDoug Rabson 	      p + 36,
410c19800e8SDoug Rabson 	      output_message_buffer->length);
411c19800e8SDoug Rabson   return GSS_S_COMPLETE;
412c19800e8SDoug Rabson }
413c19800e8SDoug Rabson 
_gsskrb5_unwrap(OM_uint32 * minor_status,const gss_ctx_id_t context_handle,const gss_buffer_t input_message_buffer,gss_buffer_t output_message_buffer,int * conf_state,gss_qop_t * qop_state)414ae771770SStanislav Sedov OM_uint32 GSSAPI_CALLCONV _gsskrb5_unwrap
415c19800e8SDoug Rabson            (OM_uint32 * minor_status,
416c19800e8SDoug Rabson             const gss_ctx_id_t context_handle,
417c19800e8SDoug Rabson             const gss_buffer_t input_message_buffer,
418c19800e8SDoug Rabson             gss_buffer_t output_message_buffer,
419c19800e8SDoug Rabson             int * conf_state,
420c19800e8SDoug Rabson             gss_qop_t * qop_state
421c19800e8SDoug Rabson            )
422c19800e8SDoug Rabson {
423c19800e8SDoug Rabson   krb5_keyblock *key;
424c19800e8SDoug Rabson   krb5_context context;
425c19800e8SDoug Rabson   OM_uint32 ret;
426c19800e8SDoug Rabson   krb5_keytype keytype;
427c19800e8SDoug Rabson   gsskrb5_ctx ctx = (gsskrb5_ctx) context_handle;
428c19800e8SDoug Rabson 
429c19800e8SDoug Rabson   output_message_buffer->value = NULL;
430c19800e8SDoug Rabson   output_message_buffer->length = 0;
431ae771770SStanislav Sedov   if (qop_state != NULL)
432ae771770SStanislav Sedov       *qop_state = GSS_C_QOP_DEFAULT;
433c19800e8SDoug Rabson 
434c19800e8SDoug Rabson   GSSAPI_KRB5_INIT (&context);
435c19800e8SDoug Rabson 
436ae771770SStanislav Sedov   if (ctx->more_flags & IS_CFX)
437ae771770SStanislav Sedov       return _gssapi_unwrap_cfx (minor_status, ctx, context,
438ae771770SStanislav Sedov 				 input_message_buffer, output_message_buffer,
439ae771770SStanislav Sedov 				 conf_state, qop_state);
440ae771770SStanislav Sedov 
441c19800e8SDoug Rabson   HEIMDAL_MUTEX_lock(&ctx->ctx_id_mutex);
442c19800e8SDoug Rabson   ret = _gsskrb5i_get_token_key(ctx, context, &key);
443c19800e8SDoug Rabson   HEIMDAL_MUTEX_unlock(&ctx->ctx_id_mutex);
444c19800e8SDoug Rabson   if (ret) {
445c19800e8SDoug Rabson       *minor_status = ret;
446c19800e8SDoug Rabson       return GSS_S_FAILURE;
447c19800e8SDoug Rabson   }
448c19800e8SDoug Rabson   krb5_enctype_to_keytype (context, key->keytype, &keytype);
449c19800e8SDoug Rabson 
450c19800e8SDoug Rabson   *minor_status = 0;
451c19800e8SDoug Rabson 
452c19800e8SDoug Rabson   switch (keytype) {
453c19800e8SDoug Rabson   case KEYTYPE_DES :
454ae771770SStanislav Sedov #ifdef HEIM_WEAK_CRYPTO
455c19800e8SDoug Rabson       ret = unwrap_des (minor_status, ctx,
456c19800e8SDoug Rabson 			input_message_buffer, output_message_buffer,
457c19800e8SDoug Rabson 			conf_state, qop_state, key);
458ae771770SStanislav Sedov #else
459ae771770SStanislav Sedov       ret = GSS_S_FAILURE;
460ae771770SStanislav Sedov #endif
461c19800e8SDoug Rabson       break;
462c19800e8SDoug Rabson   case KEYTYPE_DES3 :
463c19800e8SDoug Rabson       ret = unwrap_des3 (minor_status, ctx, context,
464c19800e8SDoug Rabson 			 input_message_buffer, output_message_buffer,
465c19800e8SDoug Rabson 			 conf_state, qop_state, key);
466c19800e8SDoug Rabson       break;
467c19800e8SDoug Rabson   case KEYTYPE_ARCFOUR:
468c19800e8SDoug Rabson   case KEYTYPE_ARCFOUR_56:
469c19800e8SDoug Rabson       ret = _gssapi_unwrap_arcfour (minor_status, ctx, context,
470c19800e8SDoug Rabson 				    input_message_buffer, output_message_buffer,
471c19800e8SDoug Rabson 				    conf_state, qop_state, key);
472c19800e8SDoug Rabson       break;
473c19800e8SDoug Rabson   default :
474ae771770SStanislav Sedov       abort();
475c19800e8SDoug Rabson       break;
476c19800e8SDoug Rabson   }
477c19800e8SDoug Rabson   krb5_free_keyblock (context, key);
478c19800e8SDoug Rabson   return ret;
479c19800e8SDoug Rabson }
480