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