1/*	$NetBSD: prf.c,v 1.1.1.1 2011/04/13 18:14:45 elric Exp $	*/
2
3/*
4 * Copyright (c) 2007 Kungliga Tekniska Högskolan
5 * (Royal Institute of Technology, Stockholm, Sweden).
6 * All rights reserved.
7 *
8 * Redistribution and use in source and binary forms, with or without
9 * modification, are permitted provided that the following conditions
10 * are met:
11 *
12 * 1. Redistributions of source code must retain the above copyright
13 *    notice, this list of conditions and the following disclaimer.
14 *
15 * 2. Redistributions in binary form must reproduce the above copyright
16 *    notice, this list of conditions and the following disclaimer in the
17 *    documentation and/or other materials provided with the distribution.
18 *
19 * 3. Neither the name of the Institute nor the names of its contributors
20 *    may be used to endorse or promote products derived from this software
21 *    without specific prior written permission.
22 *
23 * THIS SOFTWARE IS PROVIDED BY THE INSTITUTE AND CONTRIBUTORS ``AS IS'' AND
24 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
25 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
26 * ARE DISCLAIMED.  IN NO EVENT SHALL THE INSTITUTE OR CONTRIBUTORS BE LIABLE
27 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
28 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
29 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
30 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
31 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
32 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
33 * SUCH DAMAGE.
34 */
35
36#include "gsskrb5_locl.h"
37
38OM_uint32 GSSAPI_CALLCONV
39_gsskrb5_pseudo_random(OM_uint32 *minor_status,
40		       gss_ctx_id_t context_handle,
41		       int prf_key,
42		       const gss_buffer_t prf_in,
43		       ssize_t desired_output_len,
44		       gss_buffer_t prf_out)
45{
46    gsskrb5_ctx ctx = (gsskrb5_ctx)context_handle;
47    krb5_context context;
48    krb5_error_code ret;
49    krb5_crypto crypto;
50    krb5_data input, output;
51    uint32_t num;
52    unsigned char *p;
53    krb5_keyblock *key = NULL;
54
55    if (ctx == NULL) {
56	*minor_status = 0;
57	return GSS_S_NO_CONTEXT;
58    }
59
60    if (desired_output_len <= 0) {
61	*minor_status = 0;
62	return GSS_S_FAILURE;
63    }
64
65    GSSAPI_KRB5_INIT (&context);
66
67    switch(prf_key) {
68    case GSS_C_PRF_KEY_FULL:
69	_gsskrb5i_get_acceptor_subkey(ctx, context, &key);
70	break;
71    case GSS_C_PRF_KEY_PARTIAL:
72	_gsskrb5i_get_initiator_subkey(ctx, context, &key);
73	break;
74    default:
75	_gsskrb5_set_status(EINVAL, "unknown kerberos prf_key");
76	*minor_status = EINVAL;
77	return GSS_S_FAILURE;
78    }
79
80    if (key == NULL) {
81	_gsskrb5_set_status(EINVAL, "no prf_key found");
82	*minor_status = EINVAL;
83	return GSS_S_FAILURE;
84    }
85
86    ret = krb5_crypto_init(context, key, 0, &crypto);
87    krb5_free_keyblock (context, key);
88    if (ret) {
89	*minor_status = ret;
90	return GSS_S_FAILURE;
91    }
92
93    prf_out->value = malloc(desired_output_len);
94    if (prf_out->value == NULL) {
95	_gsskrb5_set_status(GSS_KRB5_S_KG_INPUT_TOO_LONG, "Out of memory");
96	*minor_status = GSS_KRB5_S_KG_INPUT_TOO_LONG;
97	krb5_crypto_destroy(context, crypto);
98	return GSS_S_FAILURE;
99    }
100    prf_out->length = desired_output_len;
101
102    HEIMDAL_MUTEX_lock(&ctx->ctx_id_mutex);
103
104    input.length = prf_in->length + 4;
105    input.data = malloc(prf_in->length + 4);
106    if (input.data == NULL) {
107	OM_uint32 junk;
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(((unsigned char *)input.data) + 4, prf_in->value, prf_in->length);
116
117    num = 0;
118    p = prf_out->value;
119    while(desired_output_len > 0) {
120	_gsskrb5_encode_om_uint32(num, input.data);
121	ret = krb5_crypto_prf(context, crypto, &input, &output);
122	if (ret) {
123	    OM_uint32 junk;
124	    *minor_status = ret;
125	    free(input.data);
126	    gss_release_buffer(&junk, prf_out);
127	    krb5_crypto_destroy(context, crypto);
128	    HEIMDAL_MUTEX_unlock(&ctx->ctx_id_mutex);
129	    return GSS_S_FAILURE;
130	}
131	memcpy(p, output.data, min(desired_output_len, output.length));
132	p += output.length;
133	desired_output_len -= output.length;
134	krb5_data_free(&output);
135	num++;
136    }
137    free(input.data);
138
139    krb5_crypto_destroy(context, crypto);
140
141    HEIMDAL_MUTEX_unlock(&ctx->ctx_id_mutex);
142
143    return GSS_S_COMPLETE;
144}
145