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