1 /*	$NetBSD: unwrap.c,v 1.1.1.2 2014/04/24 12:45:29 pettai Exp $	*/
2 
3 /*
4  * Copyright (c) 1997 - 2004 Kungliga Tekniska Högskolan
5  * (Royal Institute of Technology, Stockholm, Sweden).
6  * All rights reserved.
7  *
8  * Redistribution and use in source and binary forms, with or without
9  * modification, are permitted provided that the following conditions
10  * are met:
11  *
12  * 1. Redistributions of source code must retain the above copyright
13  *    notice, this list of conditions and the following disclaimer.
14  *
15  * 2. Redistributions in binary form must reproduce the above copyright
16  *    notice, this list of conditions and the following disclaimer in the
17  *    documentation and/or other materials provided with the distribution.
18  *
19  * 3. Neither the name of the Institute nor the names of its contributors
20  *    may be used to endorse or promote products derived from this software
21  *    without specific prior written permission.
22  *
23  * THIS SOFTWARE IS PROVIDED BY THE INSTITUTE AND CONTRIBUTORS ``AS IS'' AND
24  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
25  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
26  * ARE DISCLAIMED.  IN NO EVENT SHALL THE INSTITUTE OR CONTRIBUTORS BE LIABLE
27  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
28  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
29  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
30  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
31  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
32  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
33  * SUCH DAMAGE.
34  */
35 
36 #include "gsskrb5_locl.h"
37 
38 #ifdef HEIM_WEAK_CRYPTO
39 
40 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)41 unwrap_des
42            (OM_uint32 * minor_status,
43             const gsskrb5_ctx context_handle,
44             const gss_buffer_t input_message_buffer,
45             gss_buffer_t output_message_buffer,
46             int * conf_state,
47             gss_qop_t * qop_state,
48 	    krb5_keyblock *key
49            )
50 {
51   u_char *p, *seq;
52   size_t len;
53   EVP_MD_CTX *md5;
54   u_char hash[16];
55   EVP_CIPHER_CTX des_ctx;
56   DES_key_schedule schedule;
57   DES_cblock deskey;
58   DES_cblock zero;
59   size_t i;
60   uint32_t seq_number;
61   size_t padlength;
62   OM_uint32 ret;
63   int cstate;
64   int cmp;
65   int token_len;
66 
67   if (IS_DCE_STYLE(context_handle)) {
68      token_len = 22 + 8 + 15; /* 45 */
69   } else {
70      token_len = input_message_buffer->length;
71   }
72 
73   p = input_message_buffer->value;
74   ret = _gsskrb5_verify_header (&p,
75 				   token_len,
76 				   "\x02\x01",
77 				   GSS_KRB5_MECHANISM);
78   if (ret)
79       return ret;
80 
81   if (memcmp (p, "\x00\x00", 2) != 0)
82     return GSS_S_BAD_SIG;
83   p += 2;
84   if (memcmp (p, "\x00\x00", 2) == 0) {
85       cstate = 1;
86   } else if (memcmp (p, "\xFF\xFF", 2) == 0) {
87       cstate = 0;
88   } else
89       return GSS_S_BAD_MIC;
90   p += 2;
91   if(conf_state != NULL)
92       *conf_state = cstate;
93   if (memcmp (p, "\xff\xff", 2) != 0)
94     return GSS_S_DEFECTIVE_TOKEN;
95   p += 2;
96   p += 16;
97 
98   len = p - (u_char *)input_message_buffer->value;
99 
100   if(cstate) {
101       /* decrypt data */
102       memcpy (&deskey, key->keyvalue.data, sizeof(deskey));
103       memset (&zero, 0, sizeof(zero));
104 
105       for (i = 0; i < sizeof(deskey); ++i)
106 	  deskey[i] ^= 0xf0;
107 
108 
109       EVP_CIPHER_CTX_init(&des_ctx);
110       EVP_CipherInit_ex(&des_ctx, EVP_des_cbc(), NULL, deskey, zero, 0);
111       EVP_Cipher(&des_ctx, p, p, input_message_buffer->length - len);
112       EVP_CIPHER_CTX_cleanup(&des_ctx);
113 
114       memset (&schedule, 0, sizeof(schedule));
115   }
116 
117   if (IS_DCE_STYLE(context_handle)) {
118     padlength = 0;
119   } else {
120     /* check pad */
121     ret = _gssapi_verify_pad(input_message_buffer,
122 			     input_message_buffer->length - len,
123 			     &padlength);
124     if (ret)
125         return ret;
126   }
127 
128   md5 = EVP_MD_CTX_create();
129   EVP_DigestInit_ex(md5, EVP_md5(), NULL);
130   EVP_DigestUpdate(md5, p - 24, 8);
131   EVP_DigestUpdate(md5, p, input_message_buffer->length - len);
132   EVP_DigestFinal_ex(md5, hash, NULL);
133   EVP_MD_CTX_destroy(md5);
134 
135   memset (&zero, 0, sizeof(zero));
136   memcpy (&deskey, key->keyvalue.data, sizeof(deskey));
137   DES_set_key_unchecked (&deskey, &schedule);
138   DES_cbc_cksum ((void *)hash, (void *)hash, sizeof(hash),
139 		 &schedule, &zero);
140   if (ct_memcmp (p - 8, hash, 8) != 0)
141     return GSS_S_BAD_MIC;
142 
143   /* verify sequence number */
144 
145   HEIMDAL_MUTEX_lock(&context_handle->ctx_id_mutex);
146 
147   p -= 16;
148 
149   EVP_CIPHER_CTX_init(&des_ctx);
150   EVP_CipherInit_ex(&des_ctx, EVP_des_cbc(), NULL, key->keyvalue.data, hash, 0);
151   EVP_Cipher(&des_ctx, p, p, 8);
152   EVP_CIPHER_CTX_cleanup(&des_ctx);
153 
154   memset (deskey, 0, sizeof(deskey));
155   memset (&schedule, 0, sizeof(schedule));
156 
157   seq = p;
158   _gsskrb5_decode_om_uint32(seq, &seq_number);
159 
160   if (context_handle->more_flags & LOCAL)
161       cmp = ct_memcmp(&seq[4], "\xff\xff\xff\xff", 4);
162   else
163       cmp = ct_memcmp(&seq[4], "\x00\x00\x00\x00", 4);
164 
165   if (cmp != 0) {
166     HEIMDAL_MUTEX_unlock(&context_handle->ctx_id_mutex);
167     return GSS_S_BAD_MIC;
168   }
169 
170   ret = _gssapi_msg_order_check(context_handle->order, seq_number);
171   if (ret) {
172     HEIMDAL_MUTEX_unlock(&context_handle->ctx_id_mutex);
173     return ret;
174   }
175 
176   HEIMDAL_MUTEX_unlock(&context_handle->ctx_id_mutex);
177 
178   /* copy out data */
179 
180   output_message_buffer->length = input_message_buffer->length
181     - len - padlength - 8;
182   output_message_buffer->value  = malloc(output_message_buffer->length);
183   if(output_message_buffer->length != 0 && output_message_buffer->value == NULL)
184       return GSS_S_FAILURE;
185   memcpy (output_message_buffer->value,
186 	  p + 24,
187 	  output_message_buffer->length);
188   return GSS_S_COMPLETE;
189 }
190 #endif
191 
192 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)193 unwrap_des3
194            (OM_uint32 * minor_status,
195             const gsskrb5_ctx context_handle,
196 	    krb5_context context,
197             const gss_buffer_t input_message_buffer,
198             gss_buffer_t output_message_buffer,
199             int * conf_state,
200             gss_qop_t * qop_state,
201 	    krb5_keyblock *key
202            )
203 {
204   u_char *p;
205   size_t len;
206   u_char *seq;
207   krb5_data seq_data;
208   u_char cksum[20];
209   uint32_t seq_number;
210   size_t padlength;
211   OM_uint32 ret;
212   int cstate;
213   krb5_crypto crypto;
214   Checksum csum;
215   int cmp;
216   int token_len;
217 
218   if (IS_DCE_STYLE(context_handle)) {
219      token_len = 34 + 8 + 15; /* 57 */
220   } else {
221      token_len = input_message_buffer->length;
222   }
223 
224   p = input_message_buffer->value;
225   ret = _gsskrb5_verify_header (&p,
226 				   token_len,
227 				   "\x02\x01",
228 				   GSS_KRB5_MECHANISM);
229   if (ret)
230       return ret;
231 
232   if (memcmp (p, "\x04\x00", 2) != 0) /* HMAC SHA1 DES3_KD */
233     return GSS_S_BAD_SIG;
234   p += 2;
235   if (ct_memcmp (p, "\x02\x00", 2) == 0) {
236     cstate = 1;
237   } else if (ct_memcmp (p, "\xff\xff", 2) == 0) {
238     cstate = 0;
239   } else
240     return GSS_S_BAD_MIC;
241   p += 2;
242   if(conf_state != NULL)
243     *conf_state = cstate;
244   if (ct_memcmp (p, "\xff\xff", 2) != 0)
245     return GSS_S_DEFECTIVE_TOKEN;
246   p += 2;
247   p += 28;
248 
249   len = p - (u_char *)input_message_buffer->value;
250 
251   if(cstate) {
252       /* decrypt data */
253       krb5_data tmp;
254 
255       ret = krb5_crypto_init(context, key,
256 			     ETYPE_DES3_CBC_NONE, &crypto);
257       if (ret) {
258 	  *minor_status = ret;
259 	  return GSS_S_FAILURE;
260       }
261       ret = krb5_decrypt(context, crypto, KRB5_KU_USAGE_SEAL,
262 			 p, input_message_buffer->length - len, &tmp);
263       krb5_crypto_destroy(context, crypto);
264       if (ret) {
265 	  *minor_status = ret;
266 	  return GSS_S_FAILURE;
267       }
268       assert (tmp.length == input_message_buffer->length - len);
269 
270       memcpy (p, tmp.data, tmp.length);
271       krb5_data_free(&tmp);
272   }
273 
274   if (IS_DCE_STYLE(context_handle)) {
275     padlength = 0;
276   } else {
277     /* check pad */
278     ret = _gssapi_verify_pad(input_message_buffer,
279 			     input_message_buffer->length - len,
280 			     &padlength);
281     if (ret)
282         return ret;
283   }
284 
285   /* verify sequence number */
286 
287   HEIMDAL_MUTEX_lock(&context_handle->ctx_id_mutex);
288 
289   p -= 28;
290 
291   ret = krb5_crypto_init(context, key,
292 			 ETYPE_DES3_CBC_NONE, &crypto);
293   if (ret) {
294       *minor_status = ret;
295       HEIMDAL_MUTEX_unlock(&context_handle->ctx_id_mutex);
296       return GSS_S_FAILURE;
297   }
298   {
299       DES_cblock ivec;
300 
301       memcpy(&ivec, p + 8, 8);
302       ret = krb5_decrypt_ivec (context,
303 			       crypto,
304 			       KRB5_KU_USAGE_SEQ,
305 			       p, 8, &seq_data,
306 			       &ivec);
307   }
308   krb5_crypto_destroy (context, crypto);
309   if (ret) {
310       *minor_status = ret;
311       HEIMDAL_MUTEX_unlock(&context_handle->ctx_id_mutex);
312       return GSS_S_FAILURE;
313   }
314   if (seq_data.length != 8) {
315       krb5_data_free (&seq_data);
316       *minor_status = 0;
317       HEIMDAL_MUTEX_unlock(&context_handle->ctx_id_mutex);
318       return GSS_S_BAD_MIC;
319   }
320 
321   seq = seq_data.data;
322   _gsskrb5_decode_om_uint32(seq, &seq_number);
323 
324   if (context_handle->more_flags & LOCAL)
325       cmp = ct_memcmp(&seq[4], "\xff\xff\xff\xff", 4);
326   else
327       cmp = ct_memcmp(&seq[4], "\x00\x00\x00\x00", 4);
328 
329   krb5_data_free (&seq_data);
330   if (cmp != 0) {
331       *minor_status = 0;
332       HEIMDAL_MUTEX_unlock(&context_handle->ctx_id_mutex);
333       return GSS_S_BAD_MIC;
334   }
335 
336   ret = _gssapi_msg_order_check(context_handle->order, seq_number);
337   if (ret) {
338       *minor_status = 0;
339       HEIMDAL_MUTEX_unlock(&context_handle->ctx_id_mutex);
340       return ret;
341   }
342 
343   HEIMDAL_MUTEX_unlock(&context_handle->ctx_id_mutex);
344 
345   /* verify checksum */
346 
347   memcpy (cksum, p + 8, 20);
348 
349   memcpy (p + 20, p - 8, 8);
350 
351   csum.cksumtype = CKSUMTYPE_HMAC_SHA1_DES3;
352   csum.checksum.length = 20;
353   csum.checksum.data   = cksum;
354 
355   ret = krb5_crypto_init(context, key, 0, &crypto);
356   if (ret) {
357       *minor_status = ret;
358       return GSS_S_FAILURE;
359   }
360 
361   ret = krb5_verify_checksum (context, crypto,
362 			      KRB5_KU_USAGE_SIGN,
363 			      p + 20,
364 			      input_message_buffer->length - len + 8,
365 			      &csum);
366   krb5_crypto_destroy (context, crypto);
367   if (ret) {
368       *minor_status = ret;
369       return GSS_S_FAILURE;
370   }
371 
372   /* copy out data */
373 
374   output_message_buffer->length = input_message_buffer->length
375     - len - padlength - 8;
376   output_message_buffer->value  = malloc(output_message_buffer->length);
377   if(output_message_buffer->length != 0 && output_message_buffer->value == NULL)
378       return GSS_S_FAILURE;
379   memcpy (output_message_buffer->value,
380 	  p + 36,
381 	  output_message_buffer->length);
382   return GSS_S_COMPLETE;
383 }
384 
_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)385 OM_uint32 GSSAPI_CALLCONV _gsskrb5_unwrap
386            (OM_uint32 * minor_status,
387             const gss_ctx_id_t context_handle,
388             const gss_buffer_t input_message_buffer,
389             gss_buffer_t output_message_buffer,
390             int * conf_state,
391             gss_qop_t * qop_state
392            )
393 {
394   krb5_keyblock *key;
395   krb5_context context;
396   OM_uint32 ret;
397   krb5_keytype keytype;
398   gsskrb5_ctx ctx = (gsskrb5_ctx) context_handle;
399 
400   output_message_buffer->value = NULL;
401   output_message_buffer->length = 0;
402   if (qop_state != NULL)
403       *qop_state = GSS_C_QOP_DEFAULT;
404 
405   GSSAPI_KRB5_INIT (&context);
406 
407   if (ctx->more_flags & IS_CFX)
408       return _gssapi_unwrap_cfx (minor_status, ctx, context,
409 				 input_message_buffer, output_message_buffer,
410 				 conf_state, qop_state);
411 
412   HEIMDAL_MUTEX_lock(&ctx->ctx_id_mutex);
413   ret = _gsskrb5i_get_token_key(ctx, context, &key);
414   HEIMDAL_MUTEX_unlock(&ctx->ctx_id_mutex);
415   if (ret) {
416       *minor_status = ret;
417       return GSS_S_FAILURE;
418   }
419   krb5_enctype_to_keytype (context, key->keytype, &keytype);
420 
421   *minor_status = 0;
422 
423   switch (keytype) {
424   case KEYTYPE_DES :
425 #ifdef HEIM_WEAK_CRYPTO
426       ret = unwrap_des (minor_status, ctx,
427 			input_message_buffer, output_message_buffer,
428 			conf_state, qop_state, key);
429 #else
430       ret = GSS_S_FAILURE;
431 #endif
432       break;
433   case KEYTYPE_DES3 :
434       ret = unwrap_des3 (minor_status, ctx, context,
435 			 input_message_buffer, output_message_buffer,
436 			 conf_state, qop_state, key);
437       break;
438   case KEYTYPE_ARCFOUR:
439   case KEYTYPE_ARCFOUR_56:
440       ret = _gssapi_unwrap_arcfour (minor_status, ctx, context,
441 				    input_message_buffer, output_message_buffer,
442 				    conf_state, qop_state, key);
443       break;
444   default :
445       abort();
446       break;
447   }
448   krb5_free_keyblock (context, key);
449   return ret;
450 }
451