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