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

/* [<][>][^][v][top][bottom][index][help] */
   1 /*
   2  * Copyright (c) 1997 - 2003 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 verify_mic_des
  40            (OM_uint32 * minor_status,
  41             const gsskrb5_ctx context_handle,
  42             krb5_context context,
  43             const gss_buffer_t message_buffer,
  44             const gss_buffer_t token_buffer,
  45             gss_qop_t * qop_state,
  46             krb5_keyblock *key,
  47             char *type
  48             )
  49 {
  50   u_char *p;
  51   MD5_CTX md5;
  52   u_char hash[16], *seq;
  53   DES_key_schedule schedule;
  54   DES_cblock zero;
  55   DES_cblock deskey;
  56   uint32_t seq_number;
  57   OM_uint32 ret;
  58   int cmp;
  59 
  60   p = token_buffer->value;
  61   ret = _gsskrb5_verify_header (&p,
  62                                    token_buffer->length,
  63                                    type,
  64                                    GSS_KRB5_MECHANISM);
  65   if (ret)
  66       return ret;
  67 
  68   if (memcmp(p, "\x00\x00", 2) != 0)
  69       return GSS_S_BAD_SIG;
  70   p += 2;
  71   if (memcmp (p, "\xff\xff\xff\xff", 4) != 0)
  72     return GSS_S_BAD_MIC;
  73   p += 4;
  74   p += 16;
  75 
  76   /* verify checksum */
  77   MD5_Init (&md5);
  78   MD5_Update (&md5, p - 24, 8);
  79   MD5_Update (&md5, message_buffer->value,
  80              message_buffer->length);
  81   MD5_Final (hash, &md5);
  82 
  83   memset (&zero, 0, sizeof(zero));
  84   memcpy (&deskey, key->keyvalue.data, sizeof(deskey));
  85 
  86   DES_set_key_unchecked (&deskey, &schedule);
  87   DES_cbc_cksum ((void *)hash, (void *)hash, sizeof(hash),
  88                  &schedule, &zero);
  89   if (memcmp (p - 8, hash, 8) != 0) {
  90     memset (deskey, 0, sizeof(deskey));
  91     memset (&schedule, 0, sizeof(schedule));
  92     return GSS_S_BAD_MIC;
  93   }
  94 
  95   /* verify sequence number */
  96 
  97   HEIMDAL_MUTEX_lock(&context_handle->ctx_id_mutex);
  98 
  99   p -= 16;
 100   DES_set_key_unchecked (&deskey, &schedule);
 101   DES_cbc_encrypt ((void *)p, (void *)p, 8,
 102                    &schedule, (DES_cblock *)hash, DES_DECRYPT);
 103 
 104   memset (deskey, 0, sizeof(deskey));
 105   memset (&schedule, 0, sizeof(schedule));
 106 
 107   seq = p;
 108   _gsskrb5_decode_om_uint32(seq, &seq_number);
 109 
 110   if (context_handle->more_flags & LOCAL)
 111       cmp = memcmp(&seq[4], "\xff\xff\xff\xff", 4);
 112   else
 113       cmp = memcmp(&seq[4], "\x00\x00\x00\x00", 4);
 114 
 115   if (cmp != 0) {
 116     HEIMDAL_MUTEX_unlock(&context_handle->ctx_id_mutex);
 117     return GSS_S_BAD_MIC;
 118   }
 119 
 120   ret = _gssapi_msg_order_check(context_handle->order, seq_number);
 121   if (ret) {
 122       HEIMDAL_MUTEX_unlock(&context_handle->ctx_id_mutex);
 123       return ret;
 124   }
 125 
 126   HEIMDAL_MUTEX_unlock(&context_handle->ctx_id_mutex);
 127 
 128   return GSS_S_COMPLETE;
 129 }
 130 
 131 static OM_uint32
 132 verify_mic_des3
 133            (OM_uint32 * minor_status,
 134             const gsskrb5_ctx context_handle,
 135             krb5_context context,
 136             const gss_buffer_t message_buffer,
 137             const gss_buffer_t token_buffer,
 138             gss_qop_t * qop_state,
 139             krb5_keyblock *key,
 140             char *type
 141             )
 142 {
 143   u_char *p;
 144   u_char *seq;
 145   uint32_t seq_number;
 146   OM_uint32 ret;
 147   krb5_crypto crypto;
 148   krb5_data seq_data;
 149   int cmp, docompat;
 150   Checksum csum;
 151   char *tmp;
 152   char ivec[8];
 153 
 154   p = token_buffer->value;
 155   ret = _gsskrb5_verify_header (&p,
 156                                    token_buffer->length,
 157                                    type,
 158                                    GSS_KRB5_MECHANISM);
 159   if (ret)
 160       return ret;
 161 
 162   if (memcmp(p, "\x04\x00", 2) != 0) /* SGN_ALG = HMAC SHA1 DES3-KD */
 163       return GSS_S_BAD_SIG;
 164   p += 2;
 165   if (memcmp (p, "\xff\xff\xff\xff", 4) != 0)
 166     return GSS_S_BAD_MIC;
 167   p += 4;
 168 
 169   ret = krb5_crypto_init(context, key,
 170                          ETYPE_DES3_CBC_NONE, &crypto);
 171   if (ret){
 172       *minor_status = ret;
 173       return GSS_S_FAILURE;
 174   }
 175 
 176   /* verify sequence number */
 177   docompat = 0;
 178 retry:
 179   if (docompat)
 180       memset(ivec, 0, 8);
 181   else
 182       memcpy(ivec, p + 8, 8);
 183 
 184   ret = krb5_decrypt_ivec (context,
 185                            crypto,
 186                            KRB5_KU_USAGE_SEQ,
 187                            p, 8, &seq_data, ivec);
 188   if (ret) {
 189       if (docompat++) {
 190           krb5_crypto_destroy (context, crypto);
 191           *minor_status = ret;
 192           return GSS_S_FAILURE;
 193       } else
 194           goto retry;
 195   }
 196 
 197   if (seq_data.length != 8) {
 198       krb5_data_free (&seq_data);
 199       if (docompat++) {
 200           krb5_crypto_destroy (context, crypto);
 201           return GSS_S_BAD_MIC;
 202       } else
 203           goto retry;
 204   }
 205 
 206   HEIMDAL_MUTEX_lock(&context_handle->ctx_id_mutex);
 207 
 208   seq = seq_data.data;
 209   _gsskrb5_decode_om_uint32(seq, &seq_number);
 210 
 211   if (context_handle->more_flags & LOCAL)
 212       cmp = memcmp(&seq[4], "\xff\xff\xff\xff", 4);
 213   else
 214       cmp = memcmp(&seq[4], "\x00\x00\x00\x00", 4);
 215 
 216   krb5_data_free (&seq_data);
 217   if (cmp != 0) {
 218       krb5_crypto_destroy (context, crypto);
 219       *minor_status = 0;
 220       HEIMDAL_MUTEX_unlock(&context_handle->ctx_id_mutex);
 221       return GSS_S_BAD_MIC;
 222   }
 223 
 224   ret = _gssapi_msg_order_check(context_handle->order, seq_number);
 225   if (ret) {
 226       krb5_crypto_destroy (context, crypto);
 227       *minor_status = 0;
 228       HEIMDAL_MUTEX_unlock(&context_handle->ctx_id_mutex);
 229       return ret;
 230   }
 231 
 232   /* verify checksum */
 233 
 234   tmp = malloc (message_buffer->length + 8);
 235   if (tmp == NULL) {
 236       krb5_crypto_destroy (context, crypto);
 237       HEIMDAL_MUTEX_unlock(&context_handle->ctx_id_mutex);
 238       *minor_status = ENOMEM;
 239       return GSS_S_FAILURE;
 240   }
 241 
 242   memcpy (tmp, p - 8, 8);
 243   memcpy (tmp + 8, message_buffer->value, message_buffer->length);
 244 
 245   csum.cksumtype = CKSUMTYPE_HMAC_SHA1_DES3;
 246   csum.checksum.length = 20;
 247   csum.checksum.data   = p + 8;
 248 
 249   ret = krb5_verify_checksum (context, crypto,
 250                               KRB5_KU_USAGE_SIGN,
 251                               tmp, message_buffer->length + 8,
 252                               &csum);
 253   free (tmp);
 254   if (ret) {
 255       krb5_crypto_destroy (context, crypto);
 256       *minor_status = ret;
 257       HEIMDAL_MUTEX_unlock(&context_handle->ctx_id_mutex);
 258       return GSS_S_BAD_MIC;
 259   }
 260   HEIMDAL_MUTEX_unlock(&context_handle->ctx_id_mutex);
 261 
 262   krb5_crypto_destroy (context, crypto);
 263   return GSS_S_COMPLETE;
 264 }
 265 
 266 OM_uint32
 267 _gsskrb5_verify_mic_internal
 268            (OM_uint32 * minor_status,
 269             const gsskrb5_ctx context_handle,
 270             krb5_context context,
 271             const gss_buffer_t message_buffer,
 272             const gss_buffer_t token_buffer,
 273             gss_qop_t * qop_state,
 274             char * type
 275             )
 276 {
 277     krb5_keyblock *key;
 278     OM_uint32 ret;
 279     krb5_keytype keytype;
 280 
 281     HEIMDAL_MUTEX_lock(&context_handle->ctx_id_mutex);
 282     ret = _gsskrb5i_get_token_key(context_handle, context, &key);
 283     HEIMDAL_MUTEX_unlock(&context_handle->ctx_id_mutex);
 284     if (ret) {
 285         *minor_status = ret;
 286         return GSS_S_FAILURE;
 287     }
 288     *minor_status = 0;
 289     krb5_enctype_to_keytype (context, key->keytype, &keytype);
 290     switch (keytype) {
 291     case KEYTYPE_DES :
 292         ret = verify_mic_des (minor_status, context_handle, context,
 293                               message_buffer, token_buffer, qop_state, key,
 294                               type);
 295         break;
 296     case KEYTYPE_DES3 :
 297         ret = verify_mic_des3 (minor_status, context_handle, context,
 298                                message_buffer, token_buffer, qop_state, key,
 299                                type);
 300         break;
 301     case KEYTYPE_ARCFOUR :
 302     case KEYTYPE_ARCFOUR_56 :
 303         ret = _gssapi_verify_mic_arcfour (minor_status, context_handle,
 304                                           context,
 305                                           message_buffer, token_buffer,
 306                                           qop_state, key, type);
 307         break;
 308     default :
 309         ret = _gssapi_verify_mic_cfx (minor_status, context_handle,
 310                                       context,
 311                                       message_buffer, token_buffer, qop_state,
 312                                       key);
 313         break;
 314     }
 315     krb5_free_keyblock (context, key);
 316 
 317     return ret;
 318 }
 319 
 320 OM_uint32
 321 _gsskrb5_verify_mic
 322            (OM_uint32 * minor_status,
 323             const gss_ctx_id_t context_handle,
 324             const gss_buffer_t message_buffer,
 325             const gss_buffer_t token_buffer,
 326             gss_qop_t * qop_state
 327             )
 328 {
 329     krb5_context context;
 330     OM_uint32 ret;
 331 
 332     GSSAPI_KRB5_INIT (&context);
 333 
 334     if (qop_state != NULL)
 335         *qop_state = GSS_C_QOP_DEFAULT;
 336 
 337     ret = _gsskrb5_verify_mic_internal(minor_status,
 338                                        (gsskrb5_ctx)context_handle,
 339                                        context,
 340                                        message_buffer, token_buffer,
 341                                        qop_state, "\x01\x01");
 342 
 343     return ret;
 344 }

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