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

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

DEFINITIONS

This source file includes following definitions.
  1. oid_prefix_equal
  2. export_lucid_sec_context_v1
  3. get_authtime

   1 /*
   2  * Copyright (c) 2004, PADL Software Pty Ltd.
   3  * All rights reserved.
   4  *
   5  * Redistribution and use in source and binary forms, with or without
   6  * modification, are permitted provided that the following conditions
   7  * are met:
   8  *
   9  * 1. Redistributions of source code must retain the above copyright
  10  *    notice, this list of conditions and the following disclaimer.
  11  *
  12  * 2. Redistributions in binary form must reproduce the above copyright
  13  *    notice, this list of conditions and the following disclaimer in the
  14  *    documentation and/or other materials provided with the distribution.
  15  *
  16  * 3. Neither the name of PADL Software nor the names of its contributors
  17  *    may be used to endorse or promote products derived from this software
  18  *    without specific prior written permission.
  19  *
  20  * THIS SOFTWARE IS PROVIDED BY PADL SOFTWARE AND CONTRIBUTORS ``AS IS'' AND
  21  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
  22  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
  23  * ARE DISCLAIMED.  IN NO EVENT SHALL PADL SOFTWARE OR CONTRIBUTORS BE LIABLE
  24  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
  25  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
  26  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
  27  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
  28  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
  29  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
  30  * SUCH DAMAGE.
  31  */
  32 
  33 #include "krb5/gsskrb5_locl.h"
  34 
  35 RCSID("$Id$");
  36 
  37 static int
  38 oid_prefix_equal(gss_OID oid_enc, gss_OID prefix_enc, unsigned *suffix)
     /* [<][>][^][v][top][bottom][index][help] */
  39 {
  40     int ret;
  41     heim_oid oid;
  42     heim_oid prefix;
  43 
  44     *suffix = 0;
  45 
  46     ret = der_get_oid(oid_enc->elements, oid_enc->length,
  47                       &oid, NULL);
  48     if (ret) {
  49         return 0;
  50     }
  51 
  52     ret = der_get_oid(prefix_enc->elements, prefix_enc->length,
  53                       &prefix, NULL);
  54     if (ret) {
  55         der_free_oid(&oid);
  56         return 0;
  57     }
  58 
  59     ret = 0;
  60 
  61     if (oid.length - 1 == prefix.length) {
  62         *suffix = oid.components[oid.length - 1];
  63         oid.length--;
  64         ret = (der_heim_oid_cmp(&oid, &prefix) == 0);
  65         oid.length++;
  66     }
  67 
  68     der_free_oid(&oid);
  69     der_free_oid(&prefix);
  70 
  71     return ret;
  72 }
  73 
  74 static OM_uint32 inquire_sec_context_tkt_flags
  75            (OM_uint32 *minor_status,
  76             const gsskrb5_ctx context_handle,
  77             gss_buffer_set_t *data_set)
  78 {
  79     OM_uint32 tkt_flags;
  80     unsigned char buf[4];
  81     gss_buffer_desc value;
  82 
  83     HEIMDAL_MUTEX_lock(&context_handle->ctx_id_mutex);
  84 
  85     if (context_handle->ticket == NULL) {
  86         HEIMDAL_MUTEX_unlock(&context_handle->ctx_id_mutex);
  87         _gsskrb5_set_status(EINVAL, "No ticket from which to obtain flags");
  88         *minor_status = EINVAL;
  89         return GSS_S_BAD_MECH;
  90     }
  91 
  92     tkt_flags = TicketFlags2int(context_handle->ticket->ticket.flags);
  93     HEIMDAL_MUTEX_unlock(&context_handle->ctx_id_mutex);
  94 
  95     _gsskrb5_encode_om_uint32(tkt_flags, buf);
  96     value.length = sizeof(buf);
  97     value.value = buf;
  98 
  99     return gss_add_buffer_set_member(minor_status,
 100                                      &value,
 101                                      data_set);
 102 }
 103 
 104 enum keytype { ACCEPTOR_KEY, INITIATOR_KEY, TOKEN_KEY };
 105 
 106 static OM_uint32 inquire_sec_context_get_subkey
 107            (OM_uint32 *minor_status,
 108             const gsskrb5_ctx context_handle,
 109             krb5_context context,
 110             enum keytype keytype,
 111             gss_buffer_set_t *data_set)
 112 {
 113     krb5_keyblock *key = NULL;
 114     krb5_storage *sp = NULL;
 115     krb5_data data;
 116     OM_uint32 maj_stat = GSS_S_COMPLETE;
 117     krb5_error_code ret;
 118 
 119     krb5_data_zero(&data);
 120 
 121     sp = krb5_storage_emem();
 122     if (sp == NULL) {
 123         _gsskrb5_clear_status();
 124         ret = ENOMEM;
 125         goto out;
 126     }
 127 
 128     HEIMDAL_MUTEX_lock(&context_handle->ctx_id_mutex);
 129     switch(keytype) {
 130     case ACCEPTOR_KEY:
 131         ret = _gsskrb5i_get_acceptor_subkey(context_handle, context, &key);
 132         break;
 133     case INITIATOR_KEY:
 134         ret = _gsskrb5i_get_initiator_subkey(context_handle, context, &key);
 135         break;
 136     case TOKEN_KEY:
 137         ret = _gsskrb5i_get_token_key(context_handle, context, &key);
 138         break;
 139     default:
 140         _gsskrb5_set_status(EINVAL, "%d is not a valid subkey type", keytype);
 141         ret = EINVAL;
 142         break;
 143    }
 144     HEIMDAL_MUTEX_unlock(&context_handle->ctx_id_mutex);
 145     if (ret)
 146         goto out;
 147     if (key == NULL) {
 148         _gsskrb5_set_status(EINVAL, "have no subkey of type %d", keytype);
 149         ret = EINVAL;
 150         goto out;
 151     }
 152 
 153     ret = krb5_store_keyblock(sp, *key);
 154     krb5_free_keyblock (context, key);
 155     if (ret)
 156         goto out;
 157 
 158     ret = krb5_storage_to_data(sp, &data);
 159     if (ret)
 160         goto out;
 161 
 162     {
 163         gss_buffer_desc value;
 164         
 165         value.length = data.length;
 166         value.value = data.data;
 167         
 168         maj_stat = gss_add_buffer_set_member(minor_status,
 169                                              &value,
 170                                              data_set);
 171     }
 172 
 173 out:
 174     krb5_data_free(&data);
 175     if (sp)
 176         krb5_storage_free(sp);
 177     if (ret) {
 178         *minor_status = ret;
 179         maj_stat = GSS_S_FAILURE;
 180     }
 181     return maj_stat;
 182 }
 183 
 184 static OM_uint32 inquire_sec_context_authz_data
 185            (OM_uint32 *minor_status,
 186             const gsskrb5_ctx context_handle,
 187             krb5_context context,
 188             unsigned ad_type,
 189             gss_buffer_set_t *data_set)
 190 {
 191     krb5_data data;
 192     gss_buffer_desc ad_data;
 193     OM_uint32 ret;
 194 
 195     *minor_status = 0;
 196     *data_set = GSS_C_NO_BUFFER_SET;
 197 
 198     HEIMDAL_MUTEX_lock(&context_handle->ctx_id_mutex);
 199     if (context_handle->ticket == NULL) {
 200         HEIMDAL_MUTEX_unlock(&context_handle->ctx_id_mutex);
 201         *minor_status = EINVAL;
 202         _gsskrb5_set_status(EINVAL, "No ticket to obtain authz data from");
 203         return GSS_S_NO_CONTEXT;
 204     }
 205 
 206     ret = krb5_ticket_get_authorization_data_type(context,
 207                                                   context_handle->ticket,
 208                                                   ad_type,
 209                                                   &data);
 210     HEIMDAL_MUTEX_unlock(&context_handle->ctx_id_mutex);
 211     if (ret) {
 212         *minor_status = ret;
 213         return GSS_S_FAILURE;
 214     }
 215 
 216     ad_data.value = data.data;
 217     ad_data.length = data.length;
 218 
 219     ret = gss_add_buffer_set_member(minor_status,
 220                                     &ad_data,
 221                                     data_set);
 222 
 223     krb5_data_free(&data);
 224 
 225     return ret;
 226 }
 227 
 228 static OM_uint32 inquire_sec_context_has_updated_spnego
 229            (OM_uint32 *minor_status,
 230             const gsskrb5_ctx context_handle,
 231             gss_buffer_set_t *data_set)
 232 {
 233     int is_updated = 0;
 234 
 235     *minor_status = 0;
 236     *data_set = GSS_C_NO_BUFFER_SET;
 237 
 238     /*
 239      * For Windows SPNEGO implementations, both the initiator and the
 240      * acceptor are assumed to have been updated if a "newer" [CLAR] or
 241      * different enctype is negotiated for use by the Kerberos GSS-API
 242      * mechanism.
 243      */
 244     HEIMDAL_MUTEX_lock(&context_handle->ctx_id_mutex);
 245     _gsskrb5i_is_cfx(context_handle, &is_updated);
 246     if (is_updated == 0) {
 247         krb5_keyblock *acceptor_subkey;
 248 
 249         if (context_handle->more_flags & LOCAL)
 250             acceptor_subkey = context_handle->auth_context->remote_subkey;
 251         else
 252             acceptor_subkey = context_handle->auth_context->local_subkey;
 253 
 254         if (acceptor_subkey != NULL)
 255             is_updated = (acceptor_subkey->keytype !=
 256                           context_handle->auth_context->keyblock->keytype);
 257     }
 258     HEIMDAL_MUTEX_unlock(&context_handle->ctx_id_mutex);
 259 
 260     return is_updated ? GSS_S_COMPLETE : GSS_S_FAILURE;
 261 }
 262 
 263 /*
 264  *
 265  */
 266 
 267 static OM_uint32
 268 export_lucid_sec_context_v1(OM_uint32 *minor_status,
     /* [<][>][^][v][top][bottom][index][help] */
 269                             gsskrb5_ctx context_handle,
 270                             krb5_context context,
 271                             gss_buffer_set_t *data_set)
 272 {
 273     krb5_storage *sp = NULL;
 274     OM_uint32 major_status = GSS_S_COMPLETE;
 275     krb5_error_code ret;
 276     krb5_keyblock *key = NULL;
 277     int32_t number;
 278     int is_cfx;
 279     krb5_data data;
 280 
 281     *minor_status = 0;
 282 
 283     HEIMDAL_MUTEX_lock(&context_handle->ctx_id_mutex);
 284 
 285     _gsskrb5i_is_cfx(context_handle, &is_cfx);
 286 
 287     sp = krb5_storage_emem();
 288     if (sp == NULL) {
 289         _gsskrb5_clear_status();
 290         ret = ENOMEM;
 291         goto out;
 292     }
 293 
 294     ret = krb5_store_int32(sp, 1);
 295     if (ret) goto out;
 296     ret = krb5_store_int32(sp, (context_handle->more_flags & LOCAL) ? 1 : 0);
 297     if (ret) goto out;
 298     ret = krb5_store_int32(sp, context_handle->lifetime);
 299     if (ret) goto out;
 300     krb5_auth_con_getlocalseqnumber (context,
 301                                      context_handle->auth_context,
 302                                      &number);
 303     ret = krb5_store_uint32(sp, (uint32_t)0); /* store top half as zero */
 304     if (ret) goto out;
 305     ret = krb5_store_uint32(sp, (uint32_t)number);
 306     if (ret) goto out;
 307     krb5_auth_getremoteseqnumber (context,
 308                                   context_handle->auth_context,
 309                                   &number);
 310     ret = krb5_store_uint32(sp, (uint32_t)0); /* store top half as zero */
 311     if (ret) goto out;
 312     ret = krb5_store_uint32(sp, (uint32_t)number);
 313     if (ret) goto out;
 314     ret = krb5_store_int32(sp, (is_cfx) ? 1 : 0);
 315     if (ret) goto out;
 316 
 317     ret = _gsskrb5i_get_token_key(context_handle, context, &key);
 318     if (ret) goto out;
 319 
 320     if (is_cfx == 0) {
 321         int sign_alg, seal_alg;
 322 
 323         switch (key->keytype) {
 324         case ETYPE_DES_CBC_CRC:
 325         case ETYPE_DES_CBC_MD4:
 326         case ETYPE_DES_CBC_MD5:
 327             sign_alg = 0;
 328             seal_alg = 0;
 329             break;
 330         case ETYPE_DES3_CBC_MD5:
 331         case ETYPE_DES3_CBC_SHA1:
 332             sign_alg = 4;
 333             seal_alg = 2;
 334             break;
 335         case ETYPE_ARCFOUR_HMAC_MD5:
 336         case ETYPE_ARCFOUR_HMAC_MD5_56:
 337             sign_alg = 17;
 338             seal_alg = 16;
 339             break;
 340         default:
 341             sign_alg = -1;
 342             seal_alg = -1;
 343             break;
 344         }
 345         ret = krb5_store_int32(sp, sign_alg);
 346         if (ret) goto out;
 347         ret = krb5_store_int32(sp, seal_alg);
 348         if (ret) goto out;
 349         /* ctx_key */
 350         ret = krb5_store_keyblock(sp, *key);
 351         if (ret) goto out;
 352     } else {
 353         int subkey_p = (context_handle->more_flags & ACCEPTOR_SUBKEY) ? 1 : 0;
 354 
 355         /* have_acceptor_subkey */
 356         ret = krb5_store_int32(sp, subkey_p);
 357         if (ret) goto out;
 358         /* ctx_key */
 359         ret = krb5_store_keyblock(sp, *key);
 360         if (ret) goto out;
 361         /* acceptor_subkey */
 362         if (subkey_p) {
 363             ret = krb5_store_keyblock(sp, *key);
 364             if (ret) goto out;
 365         }
 366     }
 367     ret = krb5_storage_to_data(sp, &data);
 368     if (ret) goto out;
 369 
 370     {
 371         gss_buffer_desc ad_data;
 372 
 373         ad_data.value = data.data;
 374         ad_data.length = data.length;
 375 
 376         ret = gss_add_buffer_set_member(minor_status, &ad_data, data_set);
 377         krb5_data_free(&data);
 378         if (ret)
 379             goto out;
 380     }
 381 
 382 out:
 383     if (key)
 384         krb5_free_keyblock (context, key);
 385     if (sp)
 386         krb5_storage_free(sp);
 387     if (ret) {
 388         *minor_status = ret;
 389         major_status = GSS_S_FAILURE;
 390     }
 391     HEIMDAL_MUTEX_unlock(&context_handle->ctx_id_mutex);
 392     return major_status;
 393 }
 394 
 395 static OM_uint32
 396 get_authtime(OM_uint32 *minor_status,
     /* [<][>][^][v][top][bottom][index][help] */
 397              gsskrb5_ctx ctx,
 398              gss_buffer_set_t *data_set)
 399 
 400 {
 401     gss_buffer_desc value;
 402     unsigned char buf[4];
 403     OM_uint32 authtime;
 404 
 405     HEIMDAL_MUTEX_lock(&ctx->ctx_id_mutex);
 406     if (ctx->ticket == NULL) {
 407         HEIMDAL_MUTEX_unlock(&ctx->ctx_id_mutex);
 408         _gsskrb5_set_status(EINVAL, "No ticket to obtain auth time from");
 409         *minor_status = EINVAL;
 410         return GSS_S_FAILURE;
 411     }
 412 
 413     authtime = ctx->ticket->ticket.authtime;
 414 
 415     HEIMDAL_MUTEX_unlock(&ctx->ctx_id_mutex);
 416 
 417     _gsskrb5_encode_om_uint32(authtime, buf);
 418     value.length = sizeof(buf);
 419     value.value = buf;
 420 
 421     return gss_add_buffer_set_member(minor_status,
 422                                      &value,
 423                                      data_set);
 424 }
 425 
 426 
 427 static OM_uint32
 428 get_service_keyblock
 429         (OM_uint32 *minor_status,
 430          gsskrb5_ctx ctx,
 431          gss_buffer_set_t *data_set)
 432 {
 433     krb5_storage *sp = NULL;
 434     krb5_data data;
 435     OM_uint32 maj_stat = GSS_S_COMPLETE;
 436     krb5_error_code ret = EINVAL;
 437 
 438     sp = krb5_storage_emem();
 439     if (sp == NULL) {
 440         _gsskrb5_clear_status();
 441         *minor_status = ENOMEM;
 442         return GSS_S_FAILURE;
 443     }
 444 
 445     HEIMDAL_MUTEX_lock(&ctx->ctx_id_mutex);
 446     if (ctx->service_keyblock == NULL) {
 447         HEIMDAL_MUTEX_unlock(&ctx->ctx_id_mutex);
 448         _gsskrb5_set_status(EINVAL, "No service keyblock on gssapi context");
 449         *minor_status = EINVAL;
 450         return GSS_S_FAILURE;
 451     }
 452 
 453     krb5_data_zero(&data);
 454 
 455     ret = krb5_store_keyblock(sp, *ctx->service_keyblock);
 456 
 457     HEIMDAL_MUTEX_unlock(&ctx->ctx_id_mutex);
 458 
 459     if (ret)
 460         goto out;
 461 
 462     ret = krb5_storage_to_data(sp, &data);
 463     if (ret)
 464         goto out;
 465 
 466     {
 467         gss_buffer_desc value;
 468         
 469         value.length = data.length;
 470         value.value = data.data;
 471         
 472         maj_stat = gss_add_buffer_set_member(minor_status,
 473                                              &value,
 474                                              data_set);
 475     }
 476 
 477 out:
 478     krb5_data_free(&data);
 479     if (sp)
 480         krb5_storage_free(sp);
 481     if (ret) {
 482         *minor_status = ret;
 483         maj_stat = GSS_S_FAILURE;
 484     }
 485     return maj_stat;
 486 }
 487 /*
 488  *
 489  */
 490 
 491 OM_uint32 _gsskrb5_inquire_sec_context_by_oid
 492            (OM_uint32 *minor_status,
 493             const gss_ctx_id_t context_handle,
 494             const gss_OID desired_object,
 495             gss_buffer_set_t *data_set)
 496 {
 497     krb5_context context;
 498     const gsskrb5_ctx ctx = (const gsskrb5_ctx) context_handle;
 499     unsigned suffix;
 500 
 501     if (ctx == NULL) {
 502         *minor_status = EINVAL;
 503         return GSS_S_NO_CONTEXT;
 504     }
 505 
 506     GSSAPI_KRB5_INIT (&context);
 507 
 508     if (gss_oid_equal(desired_object, GSS_KRB5_GET_TKT_FLAGS_X)) {
 509         return inquire_sec_context_tkt_flags(minor_status,
 510                                              ctx,
 511                                              data_set);
 512     } else if (gss_oid_equal(desired_object, GSS_C_PEER_HAS_UPDATED_SPNEGO)) {
 513         return inquire_sec_context_has_updated_spnego(minor_status,
 514                                                       ctx,
 515                                                       data_set);
 516     } else if (gss_oid_equal(desired_object, GSS_KRB5_GET_SUBKEY_X)) {
 517         return inquire_sec_context_get_subkey(minor_status,
 518                                               ctx,
 519                                               context,
 520                                               TOKEN_KEY,
 521                                               data_set);
 522     } else if (gss_oid_equal(desired_object, GSS_KRB5_GET_INITIATOR_SUBKEY_X)) {
 523         return inquire_sec_context_get_subkey(minor_status,
 524                                               ctx,
 525                                               context,
 526                                               INITIATOR_KEY,
 527                                               data_set);
 528     } else if (gss_oid_equal(desired_object, GSS_KRB5_GET_ACCEPTOR_SUBKEY_X)) {
 529         return inquire_sec_context_get_subkey(minor_status,
 530                                               ctx,
 531                                               context,
 532                                               ACCEPTOR_KEY,
 533                                               data_set);
 534     } else if (gss_oid_equal(desired_object, GSS_KRB5_GET_AUTHTIME_X)) {
 535         return get_authtime(minor_status, ctx, data_set);
 536     } else if (oid_prefix_equal(desired_object,
 537                                 GSS_KRB5_EXTRACT_AUTHZ_DATA_FROM_SEC_CONTEXT_X,
 538                                 &suffix)) {
 539         return inquire_sec_context_authz_data(minor_status,
 540                                               ctx,
 541                                               context,
 542                                               suffix,
 543                                               data_set);
 544     } else if (oid_prefix_equal(desired_object,
 545                                 GSS_KRB5_EXPORT_LUCID_CONTEXT_X,
 546                                 &suffix)) {
 547         if (suffix == 1)
 548             return export_lucid_sec_context_v1(minor_status,
 549                                                ctx,
 550                                                context,
 551                                                data_set);
 552         *minor_status = 0;
 553         return GSS_S_FAILURE;
 554     } else if (gss_oid_equal(desired_object, GSS_KRB5_GET_SERVICE_KEYBLOCK_X)) {
 555         return get_service_keyblock(minor_status, ctx, data_set);
 556     } else {
 557         *minor_status = 0;
 558         return GSS_S_FAILURE;
 559     }
 560 }
 561 

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