/ lib / gssapi / digest / init_sec_context.c
init_sec_context.c
  1  /*
  2   * Copyright (c) 2006 - 2008 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 "gssdigest.h"
 35  
 36  static int
 37  calculate(void *ptr,
 38  	  heim_scram_method method,
 39  	  unsigned int iterations,
 40  	  heim_scram_data *salt,
 41  	  const heim_scram_data *c1,
 42  	  const heim_scram_data *s1,
 43  	  const heim_scram_data *c2noproof,
 44  	  heim_scram_data *proof,
 45  	  heim_scram_data *server,
 46  	  heim_scram_data *sessionKey)
 47  {
 48      krb5_error_code ret;
 49      krb5_context context;
 50      krb5_storage *request, *response = NULL;
 51      krb5_data response_data;
 52      scram_id_t ctx = ptr;
 53  
 54      ret = krb5_init_context(&context);
 55      if (ret) {
 56  	return ret;
 57      }
 58      ret = krb5_kcm_storage_request(context, KCM_OP_DO_SCRAM_AUTH, &request);
 59      if (ret) {
 60  	krb5_free_context(context);
 61  	return GSS_S_FAILURE;
 62      }
 63      ret = krb5_store_stringz(request, ctx->client);
 64      if (ret == 0)
 65  	ret = krb5_store_uint32(request, iterations);
 66      if (ret == 0)
 67  	ret = krb5_store_data(request, *salt);
 68      if (ret == 0)
 69  	ret = krb5_store_data(request, *c1);
 70      if (ret == 0)
 71  	ret = krb5_store_data(request, *s1);
 72      if (ret == 0)
 73  	ret = krb5_store_data(request, *c2noproof);
 74      if (ret == 0)
 75  	ret = krb5_kcm_call(context, request, &response, &response_data);
 76      
 77      krb5_free_context(context);
 78      krb5_storage_free(request);
 79      if (ret == 0)
 80      ret = krb5_ret_data(response, proof);
 81      if (ret == 0)
 82  	ret = krb5_ret_data(response, server);
 83      if (ret == 0)
 84  	ret = krb5_ret_data(response, sessionKey);
 85      if (ret)
 86  	ret = KRB5_CC_IO;
 87      
 88      if (response)
 89  	krb5_storage_free(response);
 90      krb5_data_free(&response_data);
 91  
 92      return ret;
 93      
 94  }
 95  
 96  static struct heim_scram_client scram_client = {
 97  	SCRAM_CLIENT_VERSION_1,
 98  	calculate
 99  };
100      
101  OM_uint32
102  _gss_scram_init_sec_context(OM_uint32 * minor_status,
103  			    const gss_cred_id_t initiator_cred_handle,
104  			    gss_ctx_id_t * context_handle,
105  			    const gss_name_t target_name,
106  			    const gss_OID mech_type,
107  			    OM_uint32 req_flags,
108  			    OM_uint32 time_req,
109  			    const gss_channel_bindings_t input_chan_bindings,
110  			    const gss_buffer_t input_token,
111  			    gss_OID * actual_mech_type,
112  			    gss_buffer_t output_token,
113  			    OM_uint32 * ret_flags,
114  			    OM_uint32 * time_rec)
115  {
116      OM_uint32 major;
117      heim_scram_data in, out;
118      scram_id_t ctx;
119      int ret;
120      
121      *minor_status = 0;
122      
123      if (ret_flags)
124  	*ret_flags = 0;
125      if (time_rec)
126  	*time_rec = 0;
127      if (actual_mech_type)
128  	*actual_mech_type = GSS_C_NO_OID;
129      
130      ctx = (scram_id_t) *context_handle;
131  
132      if (actual_mech_type)
133  	*actual_mech_type = GSS_SCRAM_MECHANISM;
134      if (ret_flags)
135  	*ret_flags = 0;
136  
137      if (ctx == NULL) {
138          gss_buffer_desc outraw;
139  
140          if (initiator_cred_handle == GSS_C_NO_CREDENTIAL)
141  	    return GSS_S_FAILURE;
142  
143  	major = _gss_scram_have_cred(minor_status, (char *)initiator_cred_handle, NULL);
144  	if (major != GSS_S_COMPLETE)
145  	    return major;
146  
147  	ctx = calloc(1, sizeof(*ctx));
148  	if (ctx == NULL) {
149  	    *minor_status = ENOMEM;
150  	    return gss_mg_set_error_string(GSS_SCRAM_MECHANISM, GSS_S_FAILURE,
151  					   ENOMEM, "out of memory");
152  	}
153  	*context_handle = (gss_ctx_id_t) ctx;
154  	
155          ctx->client = strdup((char *)initiator_cred_handle);
156  	
157  	ret = heim_scram_client1(ctx->client, NULL, HEIM_SCRAM_DIGEST_SHA1,
158  				 &ctx->scram, &out);
159  	if (ret) {
160  	  _gss_scram_delete_sec_context(minor_status, context_handle, NULL);
161  	  *minor_status = ret;
162  	  return GSS_S_FAILURE;
163  	}
164  
165  	outraw.value = out.data;
166  	outraw.length = out.length;
167  
168  	major = gss_encapsulate_token(&outraw,
169  				      GSS_SCRAM_MECHANISM,
170  				      output_token);
171  	if (major) {
172  	    _gss_scram_delete_sec_context(minor_status, context_handle, NULL);
173  	    *minor_status = ENOMEM;
174  	    return GSS_S_FAILURE;
175  	}
176  
177  	ctx->flags = req_flags;
178  
179  	_gss_mg_log(1, "scram-isc-client1: %s",
180  		    ctx->client);
181  
182  	ctx->state = CLIENT2;
183  	
184  	major = GSS_S_CONTINUE_NEEDED;
185  
186      } else if (ctx->state == CLIENT2) {
187  
188  	in.data = input_token->value;
189  	in.length = input_token->length;
190  	
191  	ret = heim_scram_client2(&in, &scram_client, ctx, ctx->scram, &out);
192  	if (ret) {
193  	    _gss_scram_delete_sec_context(minor_status, context_handle, NULL);
194  	    *minor_status = ret;
195  	    return gss_mg_set_error_string(GSS_SCRAM_MECHANISM, GSS_S_FAILURE, ret,
196  					   "failed to create scram response");
197  	}
198  
199  	output_token->length = out.length;
200  	output_token->value = malloc(out.length);
201  	
202  	memcpy(output_token->value, out.data, out.length);
203  
204  	ctx->state = CLIENT3;
205  
206  	/*
207  	 * Here we have session key, pull it out and set prot ready
208  	 */
209  
210  	major = GSS_S_CONTINUE_NEEDED;
211  
212      } else if (ctx->state == CLIENT3) {
213  
214  	in.data = input_token->value;
215  	in.length = input_token->length;
216  	
217  	ret = heim_scram_client3(&in, ctx->scram);
218  	if (ret) {
219  	    _gss_scram_delete_sec_context(minor_status, context_handle, NULL);
220  	    *minor_status = ret;
221  	    return gss_mg_set_error_string(GSS_SCRAM_MECHANISM, GSS_S_FAILURE, ret,
222  					   "failed to verify server response");
223  	}
224  
225  	output_token->length = 0;
226  	output_token->value = NULL;
227  
228  	ctx->status |= STATUS_OPEN;
229  
230  	major = GSS_S_COMPLETE;
231  
232      } else {
233  	abort();
234      }
235  
236      if (ret_flags)
237  	*ret_flags = ctx->flags;
238  
239      if (time_rec)
240  	*time_rec = GSS_C_INDEFINITE;
241  
242      return major;
243  }