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