/ lib / gssapi / krb5 / prf.c
prf.c
  1  /*
  2   * Copyright (c) 2007 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 "gsskrb5_locl.h"
 35  
 36  OM_uint32 GSSAPI_CALLCONV
 37  _gsskrb5_pseudo_random(OM_uint32 *minor_status,
 38  		       gss_ctx_id_t context_handle,
 39  		       int prf_key,
 40  		       const gss_buffer_t prf_in,
 41  		       ssize_t desired_output_len,
 42  		       gss_buffer_t prf_out)
 43  {
 44      gsskrb5_ctx ctx = (gsskrb5_ctx)context_handle;
 45      krb5_context context;
 46      krb5_error_code ret;
 47      krb5_crypto crypto;
 48      krb5_data input, output;
 49      uint32_t num;
 50      OM_uint32 junk;
 51      unsigned char *p;
 52      krb5_keyblock *key = NULL;
 53      size_t dol;
 54  
 55      if (ctx == NULL) {
 56  	*minor_status = 0;
 57  	return GSS_S_NO_CONTEXT;
 58      }
 59  
 60      if (desired_output_len <= 0 || prf_in->length + 4 < prf_in->length) {
 61  	*minor_status = 0;
 62  	return GSS_S_FAILURE;
 63      }
 64      dol = desired_output_len;
 65  
 66      GSSAPI_KRB5_INIT (&context);
 67  
 68      switch(prf_key) {
 69      case GSS_C_PRF_KEY_FULL:
 70  	_gsskrb5i_get_acceptor_subkey(ctx, context, &key);
 71  	break;
 72      case GSS_C_PRF_KEY_PARTIAL:
 73  	_gsskrb5i_get_initiator_subkey(ctx, context, &key);
 74  	break;
 75      default:
 76  	_gsskrb5_set_status(EINVAL, "unknown kerberos prf_key");
 77  	*minor_status = EINVAL;
 78  	return GSS_S_FAILURE;
 79      }
 80  
 81      if (key == NULL) {
 82  	_gsskrb5_set_status(EINVAL, "no prf_key found");
 83  	*minor_status = EINVAL;
 84  	return GSS_S_FAILURE;
 85      }
 86  
 87      ret = krb5_crypto_init(context, key, 0, &crypto);
 88      krb5_free_keyblock (context, key);
 89      if (ret) {
 90  	*minor_status = ret;
 91  	return GSS_S_FAILURE;
 92      }
 93  
 94      prf_out->value = malloc(dol);
 95      if (prf_out->value == NULL) {
 96  	_gsskrb5_set_status(GSS_KRB5_S_KG_INPUT_TOO_LONG, "Out of memory");
 97  	*minor_status = GSS_KRB5_S_KG_INPUT_TOO_LONG;
 98  	krb5_crypto_destroy(context, crypto);
 99  	return GSS_S_FAILURE;
100      }
101      prf_out->length = dol;
102  
103      HEIMDAL_MUTEX_lock(&ctx->ctx_id_mutex);
104  
105      input.length = prf_in->length + 4;
106      input.data = malloc(prf_in->length + 4);
107      if (input.data == NULL) {
108  	_gsskrb5_set_status(GSS_KRB5_S_KG_INPUT_TOO_LONG, "Out of memory");
109  	*minor_status = GSS_KRB5_S_KG_INPUT_TOO_LONG;
110  	gss_release_buffer(&junk, prf_out);
111  	krb5_crypto_destroy(context, crypto);
112  	HEIMDAL_MUTEX_unlock(&ctx->ctx_id_mutex);
113  	return GSS_S_FAILURE;
114      }
115      memcpy(((uint8_t *)input.data) + 4, prf_in->value, prf_in->length);
116  
117      num = 0;
118      p = prf_out->value;
119  
120      while(dol > 0) {
121  	size_t tsize;
122  
123  	_gss_mg_encode_be_uint32(num, input.data);
124  
125  	ret = krb5_crypto_prf(context, crypto, &input, &output);
126  	if (ret) {
127  	    *minor_status = ret;
128  	    free(input.data);
129  	    gss_release_buffer(&junk, prf_out);
130  	    krb5_crypto_destroy(context, crypto);
131  	    HEIMDAL_MUTEX_unlock(&ctx->ctx_id_mutex);
132  	    return GSS_S_FAILURE;
133  	}
134  
135  	tsize = min(dol, output.length);
136  	memcpy(p, output.data, tsize);
137  	p += tsize;
138  	dol -= tsize;
139  	krb5_data_free(&output);
140  	num++;
141      }
142      free(input.data);
143  
144      krb5_crypto_destroy(context, crypto);
145  
146      HEIMDAL_MUTEX_unlock(&ctx->ctx_id_mutex);
147  
148      return GSS_S_COMPLETE;
149  }