root/source4/heimdal/lib/gssapi/krb5/unwrap.c

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

/* [<][>][^][v][top][bottom][index][help] */