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