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