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